coan  6.0.1
A C/C++ Configuration Analyzer
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
expansion_base.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2007-2013 Mike Kinghan, imk@burroingroingjoing.com *
3  * All rights reserved. *
4  * *
5  * Contributed originally by Mike Kinghan, imk@burroingroingjoing.com *
6  * *
7  * Redistribution and use in source and binary forms, with or without *
8  * modification, are permitted provided that the following conditions *
9  * are met: *
10  * *
11  * Redistributions of source code must retain the above copyright *
12  * notice, this list of conditions and the following disclaimer. *
13  * *
14  * Redistributions in binary form must reproduce the above copyright *
15  * notice, this list of conditions and the following disclaimer in the *
16  * documentation and/or other materials provided with the distribution. *
17  * *
18  * Neither the name of Mike Kinghan nor the names of its contributors *
19  * may be used to endorse or promote products derived from this software *
20  * without specific prior written permission. *
21  * *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
29  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED *
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,*
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
32  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
33  * DAMAGE. *
34  * *
35  **************************************************************************/
36 #include "expansion_base.h"
37 #include "unexplained_expansion.h"
38 #include "explained_expansion.h"
39 #include "diagnostic.h"
40 #include "reference.h"
41 #include "citable.h"
42 #include <string>
43 #include <iostream>
44 #include <iomanip>
45 #include <algorithm>
46 #include <cassert>
47 
52 using namespace std;
53 using namespace parameter_substitution;
54 
62 static string quote(string const & str)
63 {
64  string s(1,'\"');
65  for (auto ch : str) {
66  if (ch == '\\' || ch == '\"') {
67  s += '\\';
68  }
69  s += ch;
70  }
71  s += '\"';
72  return s;
73 }
74 
75 
77 : reference(ref),
78  _value(ref.invocation())
79 {
80  if (callee()->configured() && args() && callee()->parameters()) {
82  }
83 }
84 
86 {
87 
88  chewer<string> chew(chew_mode::plaintext,
89  const_cast<string &>(callee()->format()->str()));
90  for (chew(literal_space); chew; chew(literal_space)) {
91  specifier spec = specifier::read(chew);
92  if (spec) {
93  size_t param_i = spec.get_param_index();
94  switch(spec.get_handling()) {
95  case handling::substitute_arg:
96  args().set_expandable(param_i,false);
97  break;
98  case handling::substitute_quoted_arg: {
99  args().set_expandable(param_i,false);
100  auto quoted_arg = quote(args().at(param_i));
101  args()[param_i] = quoted_arg;
102  break;
103  }
104  case handling::substitute_expanded_arg:
105  args().set_expandable(param_i,true);
106  break;
107  default:
108  assert(false);
109  }
110  continue;
111  }
112  ++chew;
113  }
114 }
115 
117  string & str,
118  expansion_base const & e,
119  size_t off )
120 {
121  unsigned edits = 0;
122  chewer<string> chew(chew_mode::plaintext,str,off);
123  for ( ;(off = identifier::find_first_in(e.id(),chew)) != string::npos;
124  chew.sync()) {
125  argument_list args(chew);
126  if (e.args().str() == args.str()) {
127  size_t len = size_t(chew) - off;
128  edit(str,off,len,e.value());
129  ++edits;
130  } else {
131  chew = off + e.id().size();
132  }
133  }
134  return edits;
135 }
136 
138  expansion_base const & e,
139  size_t start)
140 {
141  unsigned edits = 0;
142  for ( ;start < args().size(); ++start) {
143  if (args().is_expandable(start)) {
144  edits += edit_buf(args()[start],e);
145  }
146  }
147  return edits;
148 }
149 
150 
152 {
153  string s;
154  string & format = const_cast<string &>(callee()->format()->str());
155  chewer<string> chew(chew_mode::plaintext,format);
156  while (chew) {
157  size_t mark = size_t(chew);
158  chew(literal_space);
159  if (size_t(chew) > mark) {
160  s += format.substr(mark,size_t(chew) - mark);
161  }
162  specifier spec = specifier::read(chew);
163  if (spec) {
164  size_t param_i = spec.get_param_index();
165  size_t next_size = s.size() + args().at(param_i).size();
166  if (next_size > max_expansion_size()) {
168  << "Argument substitution in \"" << this->reference::invocation()
169  << "\" not done. Will exceed max expansion size "
170  << max_expansion_size() << " bytes" << emit();
171  s = _value;
172  break;
173  }
174  s += args().at(param_i);
175  } else if (chew) {
176  s += *chew;
177  ++chew;
178  }
179  }
180  if (s != _value) {
181  _value = s;
182  return true;
183  }
184  return false;
185 }
186 
187 unique_ptr<expansion_base>
188 expansion_base::factory(bool explain, reference const & ref) {
189  expansion_base * peb = explain ?
190  dynamic_cast<expansion_base*>(new explained_expansion(ref))
191  : dynamic_cast<expansion_base*>(new unexplained_expansion(ref));
192  return unique_ptr<expansion_base>(peb);
193 }
194 
195 // EOF
struct unexplained_expansion encapsulates macro-expansion of a reference where the --explain option i...
unsigned edit_buf(std::string &str, expansion_base const &e, size_t off=0)
Replace all remaining occurrences of a reference throughout a string.
std::string const & at(size_t n) const
Get a range-checked [const] reference to the nth parameter.
virtual std::string const & invocation() const
Get a string representation of the reference.
Definition: reference.h:161
std::string str() const
Cast the parameter list to its canonical string representation.
void set_expansion_flags()
Assign the expand-flags of the reference's arguments, if any, in accordance with the definition...
argument_list const & args() const
Get a [const] reference to the argument_list of the reference.
Definition: reference.h:152
expansion_base(reference const &ref)
Construct from a reference.
size_t size() const
Get the number of parameters in the parameter_list_base
unsigned edit_trailing_args(expansion_base const &e, size_t start=0)
Replace all occurrences of a reference throughout a terminal segment of this expansions's arguments...
symbol::locator const & callee() const
Get a [const] the state of the referenced symbol.
Definition: reference.h:137
warning_msg< 35 > warning_incomplete_expansion
Report a macro reference not fully expanded.
Definition: diagnostic.h:721
Class argument_list encapsulates a list of macro arguments, i.e. the arguments to a macro reference...
Definition: argument_list.h:50
size_t find_first_in(std::string const &id, chewer< CharSeq > &chew)
Find the first occurrence of an identifier within a terminal segment a CharSeq
struct explained_expansion encapsulates macro-expansion of a reference when the --explain option is o...
struct parameter_substitution::format encapsulates a parameter substitution format.
bool is_expandable(size_t n) const
Say whether the nth argument, if any, is eligible for macro expansion.
std::string read(chewer< CharSeq > &chew)
Read an identifier from an chewer<CharSeq>
std::string const & id() const
Get the name of the symbol referenced.
Definition: reference.h:146
bool substitute()
Substitute the fully expanded arguments into the definition of the reference, returning true if the c...
The tag class is inserted in a diagnostic_base to tell it to emit itself.
Definition: diagnostic.h:77
handling get_handling() const
Get the handling of the specified parameter.
void sync()
Synchronise the object with the associated sequence_type
Definition: chew.h:299
static std::unique_ptr< expansion_base > factory(bool explain, reference const &ref)
Global factory of subclasses of expansion_base
void edit(std::string &str, size_t at, size_t len, std::string const &replacement)
struct paramater_substitution::specifier encapsulates a parameter substitution specifier.
unsigned short get_param_index() const
Get the index of the specified parameter.
std::shared_ptr< parameter_substitution::format const > format() const
Get a pointer to the symbol's substitution format; null if none.
Definition: symbol.h:208
static constexpr unsigned max_expansion_size()
Cut-off size for macro-expansions.
`template struct chewer<CharSeq> is a cursor-like type that is associated with a character-sequence t...
Definition: chew.h:248
std::string _value
The current expanded value.
std::string const & value() const
Get the current expanded value of the reference.
struct expansion_base is an abstract base for classes that encapsulate a mode of macro-expansion of a...
bool set_expandable(size_t n, bool expandable=false)
Set the nth expand-flag to indicate whether the nth argument, if any, is eligible for macro expansion...
static string quote(string const &str)
Return the quotation of a string.
chew_mode::literal_space const literal_space
An exemplar chew_mode::literal_space
Definition: chew.h:231