Crossfire Server, Trunk
inja.hpp
Go to the documentation of this file.
1 /*
2  ___ _ Version 3.3
3  |_ _|_ __ (_) __ _ https://github.com/pantor/inja
4  | || '_ \ | |/ _` | Licensed under the MIT License <http://opensource.org/licenses/MIT>.
5  | || | | || | (_| |
6  |___|_| |_|/ |\__,_| Copyright (c) 2018-2021 Lars Berscheid
7  |__/
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 
25 #ifndef INCLUDE_INJA_INJA_HPP_
26 #define INCLUDE_INJA_INJA_HPP_
27 
28 #include <nlohmann/json.hpp>
29 
30 #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(INJA_NOEXCEPTION)
31  #ifndef INJA_THROW
32  #define INJA_THROW(exception) throw exception
33  #endif
34 #else
35  #include <cstdlib>
36  #ifndef INJA_THROW
37  #define INJA_THROW(exception) std::abort(); std::ignore = exception
38  #endif
39  #ifndef INJA_NOEXCEPTION
40  #define INJA_NOEXCEPTION
41  #endif
42 #endif
43 
44 // #include "environment.hpp"
45 #ifndef INCLUDE_INJA_ENVIRONMENT_HPP_
46 #define INCLUDE_INJA_ENVIRONMENT_HPP_
47 
48 #include <fstream>
49 #include <iostream>
50 #include <memory>
51 #include <sstream>
52 #include <string>
53 
54 #include <nlohmann/json.hpp>
55 
56 // #include "config.hpp"
57 #ifndef INCLUDE_INJA_CONFIG_HPP_
58 #define INCLUDE_INJA_CONFIG_HPP_
59 
60 #include <functional>
61 #include <string>
62 
63 // #include "string_view.hpp"
64 // Copyright 2017-2019 by Martin Moene
65 //
66 // string-view lite, a C++17-like string_view for C++98 and later.
67 // For more information see https://github.com/martinmoene/string-view-lite
68 //
69 // Distributed under the Boost Software License, Version 1.0.
70 // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
71 
72 
73 
74 #ifndef NONSTD_SV_LITE_H_INCLUDED
75 #define NONSTD_SV_LITE_H_INCLUDED
76 
77 #define string_view_lite_MAJOR 1
78 #define string_view_lite_MINOR 4
79 #define string_view_lite_PATCH 0
80 
81 #define string_view_lite_VERSION \
82  nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY( \
83  string_view_lite_PATCH)
84 
85 #define nssv_STRINGIFY(x) nssv_STRINGIFY_(x)
86 #define nssv_STRINGIFY_(x) #x
87 
88 // string-view lite configuration:
89 
90 #define nssv_STRING_VIEW_DEFAULT 0
91 #define nssv_STRING_VIEW_NONSTD 1
92 #define nssv_STRING_VIEW_STD 2
93 
94 #if !defined(nssv_CONFIG_SELECT_STRING_VIEW)
95 #define nssv_CONFIG_SELECT_STRING_VIEW (nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD)
96 #endif
97 
98 #if defined(nssv_CONFIG_SELECT_STD_STRING_VIEW) || defined(nssv_CONFIG_SELECT_NONSTD_STRING_VIEW)
99 #error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_...
100 #endif
101 
102 #ifndef nssv_CONFIG_STD_SV_OPERATOR
103 #define nssv_CONFIG_STD_SV_OPERATOR 0
104 #endif
105 
106 #ifndef nssv_CONFIG_USR_SV_OPERATOR
107 #define nssv_CONFIG_USR_SV_OPERATOR 1
108 #endif
109 
110 #ifdef nssv_CONFIG_CONVERSION_STD_STRING
111 #define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS nssv_CONFIG_CONVERSION_STD_STRING
112 #define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS nssv_CONFIG_CONVERSION_STD_STRING
113 #endif
114 
115 #ifndef nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
116 #define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS 1
117 #endif
118 
119 #ifndef nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
120 #define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS 1
121 #endif
122 
123 // Control presence of exception handling (try and auto discover):
124 
125 #ifndef nssv_CONFIG_NO_EXCEPTIONS
126 #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
127 #define nssv_CONFIG_NO_EXCEPTIONS 0
128 #else
129 #define nssv_CONFIG_NO_EXCEPTIONS 1
130 #endif
131 #endif
132 
133 // C++ language version detection (C++20 is speculative):
134 // Note: VC14.0/1900 (VS2015) lacks too much from C++14.
135 
136 #ifndef nssv_CPLUSPLUS
137 #if defined(_MSVC_LANG) && !defined(__clang__)
138 #define nssv_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG)
139 #else
140 #define nssv_CPLUSPLUS __cplusplus
141 #endif
142 #endif
143 
144 #define nssv_CPP98_OR_GREATER (nssv_CPLUSPLUS >= 199711L)
145 #define nssv_CPP11_OR_GREATER (nssv_CPLUSPLUS >= 201103L)
146 #define nssv_CPP11_OR_GREATER_ (nssv_CPLUSPLUS >= 201103L)
147 #define nssv_CPP14_OR_GREATER (nssv_CPLUSPLUS >= 201402L)
148 #define nssv_CPP17_OR_GREATER (nssv_CPLUSPLUS >= 201703L)
149 #define nssv_CPP20_OR_GREATER (nssv_CPLUSPLUS >= 202000L)
150 
151 // use C++17 std::string_view if available and requested:
152 
153 #if nssv_CPP17_OR_GREATER && defined(__has_include)
154 #if __has_include(<string_view> )
155 #define nssv_HAVE_STD_STRING_VIEW 1
156 #else
157 #define nssv_HAVE_STD_STRING_VIEW 0
158 #endif
159 #else
160 #define nssv_HAVE_STD_STRING_VIEW 0
161 #endif
162 
163 #define nssv_USES_STD_STRING_VIEW \
164  ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || \
165  ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW))
166 
167 #define nssv_HAVE_STARTS_WITH (nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW)
168 #define nssv_HAVE_ENDS_WITH nssv_HAVE_STARTS_WITH
169 
170 //
171 // Use C++17 std::string_view:
172 //
173 
174 #if nssv_USES_STD_STRING_VIEW
175 
176 #include <string_view>
177 
178 // Extensions for std::string:
179 
180 #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
181 
182 namespace nonstd {
183 
184 template <class CharT, class Traits, class Allocator = std::allocator<CharT>>
185 std::basic_string<CharT, Traits, Allocator> to_string(std::basic_string_view<CharT, Traits> v,
186  Allocator const &a = Allocator()) {
187  return std::basic_string<CharT, Traits, Allocator>(v.begin(), v.end(), a);
188 }
189 
190 template <class CharT, class Traits, class Allocator>
191 std::basic_string_view<CharT, Traits> to_string_view(std::basic_string<CharT, Traits, Allocator> const &s) {
192  return std::basic_string_view<CharT, Traits>(s.data(), s.size());
193 }
194 
195 // Literal operators sv and _sv:
196 
197 #if nssv_CONFIG_STD_SV_OPERATOR
198 
199 using namespace std::literals::string_view_literals;
200 
201 #endif
202 
203 #if nssv_CONFIG_USR_SV_OPERATOR
204 
205 inline namespace literals {
206 inline namespace string_view_literals {
207 
208 constexpr std::string_view operator"" _sv(const char *str, size_t len) noexcept // (1)
209 {
210  return std::string_view {str, len};
211 }
212 
213 constexpr std::u16string_view operator"" _sv(const char16_t *str, size_t len) noexcept // (2)
214 {
215  return std::u16string_view {str, len};
216 }
217 
218 constexpr std::u32string_view operator"" _sv(const char32_t *str, size_t len) noexcept // (3)
219 {
220  return std::u32string_view {str, len};
221 }
222 
223 constexpr std::wstring_view operator"" _sv(const wchar_t *str, size_t len) noexcept // (4)
224 {
225  return std::wstring_view {str, len};
226 }
227 
228 } // namespace string_view_literals
229 } // namespace literals
230 
231 #endif // nssv_CONFIG_USR_SV_OPERATOR
232 
233 } // namespace nonstd
234 
235 #endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
236 
237 namespace nonstd {
238 
239 using std::basic_string_view;
240 using std::string_view;
241 using std::u16string_view;
242 using std::u32string_view;
243 using std::wstring_view;
244 
245 // literal "sv" and "_sv", see above
246 
247 using std::operator==;
248 using std::operator!=;
249 using std::operator<;
250 using std::operator<=;
251 using std::operator>;
252 using std::operator>=;
253 
254 using std::operator<<;
255 
256 } // namespace nonstd
257 
258 #else // nssv_HAVE_STD_STRING_VIEW
259 
260 //
261 // Before C++17: use string_view lite:
262 //
263 
264 // Compiler versions:
265 //
266 // MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0)
267 // MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002)
268 // MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003)
269 // MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
270 // MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
271 // MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
272 // MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
273 // MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
274 // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
275 // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017)
276 
277 #if defined(_MSC_VER) && !defined(__clang__)
278 #define nssv_COMPILER_MSVC_VER (_MSC_VER)
279 #define nssv_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900)))
280 #else
281 #define nssv_COMPILER_MSVC_VER 0
282 #define nssv_COMPILER_MSVC_VERSION 0
283 #endif
284 
285 #define nssv_COMPILER_VERSION(major, minor, patch) (10 * (10 * (major) + (minor)) + (patch))
286 
287 #if defined(__clang__)
288 #define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
289 #else
290 #define nssv_COMPILER_CLANG_VERSION 0
291 #endif
292 
293 #if defined(__GNUC__) && !defined(__clang__)
294 #define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
295 #else
296 #define nssv_COMPILER_GNUC_VERSION 0
297 #endif
298 
299 // half-open range [lo..hi):
300 #define nssv_BETWEEN(v, lo, hi) ((lo) <= (v) && (v) < (hi))
301 
302 // Presence of language and library features:
303 
304 #ifdef _HAS_CPP0X
305 #define nssv_HAS_CPP0X _HAS_CPP0X
306 #else
307 #define nssv_HAS_CPP0X 0
308 #endif
309 
310 // Unless defined otherwise below, consider VC14 as C++11 for variant-lite:
311 
312 #if nssv_COMPILER_MSVC_VER >= 1900
313 #undef nssv_CPP11_OR_GREATER
314 #define nssv_CPP11_OR_GREATER 1
315 #endif
316 
317 #define nssv_CPP11_90 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500)
318 #define nssv_CPP11_100 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600)
319 #define nssv_CPP11_110 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700)
320 #define nssv_CPP11_120 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800)
321 #define nssv_CPP11_140 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900)
322 #define nssv_CPP11_141 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910)
323 
324 #define nssv_CPP14_000 (nssv_CPP14_OR_GREATER)
325 #define nssv_CPP17_000 (nssv_CPP17_OR_GREATER)
326 
327 // Presence of C++11 language features:
328 
329 #define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140
330 #define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140
331 #define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140
332 #define nssv_HAVE_NOEXCEPT nssv_CPP11_140
333 #define nssv_HAVE_NULLPTR nssv_CPP11_100
334 #define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140
335 #define nssv_HAVE_UNICODE_LITERALS nssv_CPP11_140
336 #define nssv_HAVE_USER_DEFINED_LITERALS nssv_CPP11_140
337 #define nssv_HAVE_WCHAR16_T nssv_CPP11_100
338 #define nssv_HAVE_WCHAR32_T nssv_CPP11_100
339 
340 #if !((nssv_CPP11_OR_GREATER && nssv_COMPILER_CLANG_VERSION) || nssv_BETWEEN(nssv_COMPILER_CLANG_VERSION, 300, 400))
341 #define nssv_HAVE_STD_DEFINED_LITERALS nssv_CPP11_140
342 #else
343 #define nssv_HAVE_STD_DEFINED_LITERALS 0
344 #endif
345 
346 // Presence of C++14 language features:
347 
348 #define nssv_HAVE_CONSTEXPR_14 nssv_CPP14_000
349 
350 // Presence of C++17 language features:
351 
352 #define nssv_HAVE_NODISCARD nssv_CPP17_000
353 
354 // Presence of C++ library features:
355 
356 #define nssv_HAVE_STD_HASH nssv_CPP11_120
357 
358 // C++ feature usage:
359 
360 #if nssv_HAVE_CONSTEXPR_11
361 #define nssv_constexpr constexpr
362 #else
363 #define nssv_constexpr /*constexpr*/
364 #endif
365 
366 #if nssv_HAVE_CONSTEXPR_14
367 #define nssv_constexpr14 constexpr
368 #else
369 #define nssv_constexpr14 /*constexpr*/
370 #endif
371 
372 #if nssv_HAVE_EXPLICIT_CONVERSION
373 #define nssv_explicit explicit
374 #else
375 #define nssv_explicit /*explicit*/
376 #endif
377 
378 #if nssv_HAVE_INLINE_NAMESPACE
379 #define nssv_inline_ns inline
380 #else
381 #define nssv_inline_ns /*inline*/
382 #endif
383 
384 #if nssv_HAVE_NOEXCEPT
385 #define nssv_noexcept noexcept
386 #else
387 #define nssv_noexcept /*noexcept*/
388 #endif
389 
390 //#if nssv_HAVE_REF_QUALIFIER
391 //# define nssv_ref_qual &
392 //# define nssv_refref_qual &&
393 //#else
394 //# define nssv_ref_qual /*&*/
395 //# define nssv_refref_qual /*&&*/
396 //#endif
397 
398 #if nssv_HAVE_NULLPTR
399 #define nssv_nullptr nullptr
400 #else
401 #define nssv_nullptr NULL
402 #endif
403 
404 #if nssv_HAVE_NODISCARD
405 #define nssv_nodiscard [[nodiscard]]
406 #else
407 #define nssv_nodiscard /*[[nodiscard]]*/
408 #endif
409 
410 // Additional includes:
411 
412 #include <algorithm>
413 #include <cassert>
414 #include <iterator>
415 #include <limits>
416 #include <ostream>
417 #include <string> // std::char_traits<>
418 
419 #if !nssv_CONFIG_NO_EXCEPTIONS
420 #include <stdexcept>
421 #endif
422 
423 #if nssv_CPP11_OR_GREATER
424 #include <type_traits>
425 #endif
426 
427 // Clang, GNUC, MSVC warning suppression macros:
428 
429 #if defined(__clang__)
430 #pragma clang diagnostic ignored "-Wreserved-user-defined-literal"
431 #pragma clang diagnostic push
432 #pragma clang diagnostic ignored "-Wuser-defined-literals"
433 #elif defined(__GNUC__)
434 #pragma GCC diagnostic push
435 #pragma GCC diagnostic ignored "-Wliteral-suffix"
436 #endif // __clang__
437 
438 #if nssv_COMPILER_MSVC_VERSION >= 140
439 #define nssv_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]]
440 #define nssv_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress : code))
441 #define nssv_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable : codes))
442 #else
443 #define nssv_SUPPRESS_MSGSL_WARNING(expr)
444 #define nssv_SUPPRESS_MSVC_WARNING(code, descr)
445 #define nssv_DISABLE_MSVC_WARNINGS(codes)
446 #endif
447 
448 #if defined(__clang__)
449 #define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")
450 #elif defined(__GNUC__)
451 #define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
452 #elif nssv_COMPILER_MSVC_VERSION >= 140
453 #define nssv_RESTORE_WARNINGS() __pragma(warning(pop))
454 #else
455 #define nssv_RESTORE_WARNINGS()
456 #endif
457 
458 // Suppress the following MSVC (GSL) warnings:
459 // - C4455, non-gsl : 'operator ""sv': literal suffix identifiers that do not
460 // start with an underscore are reserved
461 // - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions;
462 // use brace initialization, gsl::narrow_cast or gsl::narow
463 // - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead
464 
465 nssv_DISABLE_MSVC_WARNINGS(4455 26481 26472)
466  // nssv_DISABLE_CLANG_WARNINGS( "-Wuser-defined-literals" )
467  // nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix )
468 
469  namespace nonstd {
470  namespace sv_lite {
471 
472 #if nssv_CPP11_OR_GREATER
473 
474  namespace detail {
475 
476  // Expect tail call optimization to make length() non-recursive:
477 
478  template <typename CharT> inline constexpr std::size_t length(CharT *s, std::size_t result = 0) {
479  return *s == '\0' ? result : length(s + 1, result + 1);
480  }
481 
482  } // namespace detail
483 
484 #endif // nssv_CPP11_OR_GREATER
485 
486  template <class CharT, class Traits = std::char_traits<CharT>> class basic_string_view;
487 
488  //
489  // basic_string_view:
490  //
491 
492  template <class CharT, class Traits /* = std::char_traits<CharT> */
493  >
494  class basic_string_view {
495  public:
496  // Member types:
497 
498  typedef Traits traits_type;
499  typedef CharT value_type;
500 
501  typedef CharT *pointer;
502  typedef CharT const *const_pointer;
503  typedef CharT &reference;
504  typedef CharT const &const_reference;
505 
506  typedef const_pointer iterator;
507  typedef const_pointer const_iterator;
508  typedef std::reverse_iterator<const_iterator> reverse_iterator;
509  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
510 
511  typedef std::size_t size_type;
512  typedef std::ptrdiff_t difference_type;
513 
514  // 24.4.2.1 Construction and assignment:
515 
516  nssv_constexpr basic_string_view() nssv_noexcept : data_(nssv_nullptr), size_(0) {}
517 
518 #if nssv_CPP11_OR_GREATER
519  nssv_constexpr basic_string_view(basic_string_view const &other) nssv_noexcept = default;
520 #else
521  nssv_constexpr basic_string_view(basic_string_view const &other) nssv_noexcept : data_(other.data_),
522  size_(other.size_) {}
523 #endif
524 
525  nssv_constexpr basic_string_view(CharT const *s, size_type count) nssv_noexcept // non-standard noexcept
526  : data_(s),
527  size_(count) {}
528 
529  nssv_constexpr basic_string_view(CharT const *s) nssv_noexcept // non-standard noexcept
530  : data_(s)
531 #if nssv_CPP17_OR_GREATER
532  ,
533  size_(Traits::length(s))
534 #elif nssv_CPP11_OR_GREATER
535  ,
536  size_(detail::length(s))
537 #else
538  ,
539  size_(Traits::length(s))
540 #endif
541  {
542  }
543 
544  // Assignment:
545 
546 #if nssv_CPP11_OR_GREATER
547  nssv_constexpr14 basic_string_view &operator=(basic_string_view const &other) nssv_noexcept = default;
548 #else
549  nssv_constexpr14 basic_string_view &operator=(basic_string_view const &other) nssv_noexcept {
550  data_ = other.data_;
551  size_ = other.size_;
552  return *this;
553  }
554 #endif
555 
556  // 24.4.2.2 Iterator support:
557 
558  nssv_constexpr const_iterator begin() const nssv_noexcept { return data_; }
559  nssv_constexpr const_iterator end() const nssv_noexcept { return data_ + size_; }
560 
561  nssv_constexpr const_iterator cbegin() const nssv_noexcept { return begin(); }
562  nssv_constexpr const_iterator cend() const nssv_noexcept { return end(); }
563 
564  nssv_constexpr const_reverse_iterator rbegin() const nssv_noexcept { return const_reverse_iterator(end()); }
565  nssv_constexpr const_reverse_iterator rend() const nssv_noexcept { return const_reverse_iterator(begin()); }
566 
567  nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept { return rbegin(); }
568  nssv_constexpr const_reverse_iterator crend() const nssv_noexcept { return rend(); }
569 
570  // 24.4.2.3 Capacity:
571 
572  nssv_constexpr size_type size() const nssv_noexcept { return size_; }
573  nssv_constexpr size_type length() const nssv_noexcept { return size_; }
574  nssv_constexpr size_type max_size() const nssv_noexcept { return (std::numeric_limits<size_type>::max)(); }
575 
576  // since C++20
577  nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept { return 0 == size_; }
578 
579  // 24.4.2.4 Element access:
580 
581  nssv_constexpr const_reference operator[](size_type pos) const { return data_at(pos); }
582 
583  nssv_constexpr14 const_reference at(size_type pos) const {
584 #if nssv_CONFIG_NO_EXCEPTIONS
585  assert(pos < size());
586 #else
587  if (pos >= size()) {
588  throw std::out_of_range("nonstd::string_view::at()");
589  }
590 #endif
591  return data_at(pos);
592  }
593 
594  nssv_constexpr const_reference front() const { return data_at(0); }
595  nssv_constexpr const_reference back() const { return data_at(size() - 1); }
596 
597  nssv_constexpr const_pointer data() const nssv_noexcept { return data_; }
598 
599  // 24.4.2.5 Modifiers:
600 
601  nssv_constexpr14 void remove_prefix(size_type n) {
602  assert(n <= size());
603  data_ += n;
604  size_ -= n;
605  }
606 
607  nssv_constexpr14 void remove_suffix(size_type n) {
608  assert(n <= size());
609  size_ -= n;
610  }
611 
612  nssv_constexpr14 void swap(basic_string_view &other) nssv_noexcept {
613  using std::swap;
614  swap(data_, other.data_);
615  swap(size_, other.size_);
616  }
617 
618  // 24.4.2.6 String operations:
619 
620  size_type copy(CharT *dest, size_type n, size_type pos = 0) const {
621 #if nssv_CONFIG_NO_EXCEPTIONS
622  assert(pos <= size());
623 #else
624  if (pos > size()) {
625  throw std::out_of_range("nonstd::string_view::copy()");
626  }
627 #endif
628  const size_type rlen = (std::min)(n, size() - pos);
629 
630  (void)Traits::copy(dest, data() + pos, rlen);
631 
632  return rlen;
633  }
634 
635  nssv_constexpr14 basic_string_view substr(size_type pos = 0, size_type n = npos) const {
636 #if nssv_CONFIG_NO_EXCEPTIONS
637  assert(pos <= size());
638 #else
639  if (pos > size()) {
640  throw std::out_of_range("nonstd::string_view::substr()");
641  }
642 #endif
643  return basic_string_view(data() + pos, (std::min)(n, size() - pos));
644  }
645 
646  // compare(), 6x:
647 
648  nssv_constexpr14 int compare(basic_string_view other) const nssv_noexcept // (1)
649  {
650  if (const int result = Traits::compare(data(), other.data(), (std::min)(size(), other.size()))) {
651  return result;
652  }
653 
654  return size() == other.size() ? 0 : size() < other.size() ? -1 : 1;
655  }
656 
657  nssv_constexpr int compare(size_type pos1, size_type n1, basic_string_view other) const // (2)
658  {
659  return substr(pos1, n1).compare(other);
660  }
661 
662  nssv_constexpr int compare(size_type pos1, size_type n1, basic_string_view other, size_type pos2,
663  size_type n2) const // (3)
664  {
665  return substr(pos1, n1).compare(other.substr(pos2, n2));
666  }
667 
668  nssv_constexpr int compare(CharT const *s) const // (4)
669  {
670  return compare(basic_string_view(s));
671  }
672 
673  nssv_constexpr int compare(size_type pos1, size_type n1, CharT const *s) const // (5)
674  {
675  return substr(pos1, n1).compare(basic_string_view(s));
676  }
677 
678  nssv_constexpr int compare(size_type pos1, size_type n1, CharT const *s, size_type n2) const // (6)
679  {
680  return substr(pos1, n1).compare(basic_string_view(s, n2));
681  }
682 
683  // 24.4.2.7 Searching:
684 
685  // starts_with(), 3x, since C++20:
686 
687  nssv_constexpr bool starts_with(basic_string_view v) const nssv_noexcept // (1)
688  {
689  return size() >= v.size() && compare(0, v.size(), v) == 0;
690  }
691 
692  nssv_constexpr bool starts_with(CharT c) const nssv_noexcept // (2)
693  {
694  return starts_with(basic_string_view(&c, 1));
695  }
696 
697  nssv_constexpr bool starts_with(CharT const *s) const // (3)
698  {
699  return starts_with(basic_string_view(s));
700  }
701 
702  // ends_with(), 3x, since C++20:
703 
704  nssv_constexpr bool ends_with(basic_string_view v) const nssv_noexcept // (1)
705  {
706  return size() >= v.size() && compare(size() - v.size(), npos, v) == 0;
707  }
708 
709  nssv_constexpr bool ends_with(CharT c) const nssv_noexcept // (2)
710  {
711  return ends_with(basic_string_view(&c, 1));
712  }
713 
714  nssv_constexpr bool ends_with(CharT const *s) const // (3)
715  {
716  return ends_with(basic_string_view(s));
717  }
718 
719  // find(), 4x:
720 
721  nssv_constexpr14 size_type find(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1)
722  {
723  return assert(v.size() == 0 || v.data() != nssv_nullptr),
724  pos >= size() ? npos : to_pos(std::search(cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq));
725  }
726 
727  nssv_constexpr14 size_type find(CharT c, size_type pos = 0) const nssv_noexcept // (2)
728  {
729  return find(basic_string_view(&c, 1), pos);
730  }
731 
732  nssv_constexpr14 size_type find(CharT const *s, size_type pos, size_type n) const // (3)
733  {
734  return find(basic_string_view(s, n), pos);
735  }
736 
737  nssv_constexpr14 size_type find(CharT const *s, size_type pos = 0) const // (4)
738  {
739  return find(basic_string_view(s), pos);
740  }
741 
742  // rfind(), 4x:
743 
744  nssv_constexpr14 size_type rfind(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1)
745  {
746  if (size() < v.size()) {
747  return npos;
748  }
749 
750  if (v.empty()) {
751  return (std::min)(size(), pos);
752  }
753 
754  const_iterator last = cbegin() + (std::min)(size() - v.size(), pos) + v.size();
755  const_iterator result = std::find_end(cbegin(), last, v.cbegin(), v.cend(), Traits::eq);
756 
757  return result != last ? size_type(result - cbegin()) : npos;
758  }
759 
760  nssv_constexpr14 size_type rfind(CharT c, size_type pos = npos) const nssv_noexcept // (2)
761  {
762  return rfind(basic_string_view(&c, 1), pos);
763  }
764 
765  nssv_constexpr14 size_type rfind(CharT const *s, size_type pos, size_type n) const // (3)
766  {
767  return rfind(basic_string_view(s, n), pos);
768  }
769 
770  nssv_constexpr14 size_type rfind(CharT const *s, size_type pos = npos) const // (4)
771  {
772  return rfind(basic_string_view(s), pos);
773  }
774 
775  // find_first_of(), 4x:
776 
777  nssv_constexpr size_type find_first_of(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1)
778  {
779  return pos >= size() ? npos
780  : to_pos(std::find_first_of(cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq));
781  }
782 
783  nssv_constexpr size_type find_first_of(CharT c, size_type pos = 0) const nssv_noexcept // (2)
784  {
785  return find_first_of(basic_string_view(&c, 1), pos);
786  }
787 
788  nssv_constexpr size_type find_first_of(CharT const *s, size_type pos, size_type n) const // (3)
789  {
790  return find_first_of(basic_string_view(s, n), pos);
791  }
792 
793  nssv_constexpr size_type find_first_of(CharT const *s, size_type pos = 0) const // (4)
794  {
795  return find_first_of(basic_string_view(s), pos);
796  }
797 
798  // find_last_of(), 4x:
799 
800  nssv_constexpr size_type find_last_of(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1)
801  {
802  return empty() ? npos
803  : pos >= size() ? find_last_of(v, size() - 1)
804  : to_pos(std::find_first_of(const_reverse_iterator(cbegin() + pos + 1), crend(),
805  v.cbegin(), v.cend(), Traits::eq));
806  }
807 
808  nssv_constexpr size_type find_last_of(CharT c, size_type pos = npos) const nssv_noexcept // (2)
809  {
810  return find_last_of(basic_string_view(&c, 1), pos);
811  }
812 
813  nssv_constexpr size_type find_last_of(CharT const *s, size_type pos, size_type count) const // (3)
814  {
815  return find_last_of(basic_string_view(s, count), pos);
816  }
817 
818  nssv_constexpr size_type find_last_of(CharT const *s, size_type pos = npos) const // (4)
819  {
820  return find_last_of(basic_string_view(s), pos);
821  }
822 
823  // find_first_not_of(), 4x:
824 
825  nssv_constexpr size_type find_first_not_of(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1)
826  {
827  return pos >= size() ? npos : to_pos(std::find_if(cbegin() + pos, cend(), not_in_view(v)));
828  }
829 
830  nssv_constexpr size_type find_first_not_of(CharT c, size_type pos = 0) const nssv_noexcept // (2)
831  {
832  return find_first_not_of(basic_string_view(&c, 1), pos);
833  }
834 
835  nssv_constexpr size_type find_first_not_of(CharT const *s, size_type pos, size_type count) const // (3)
836  {
837  return find_first_not_of(basic_string_view(s, count), pos);
838  }
839 
840  nssv_constexpr size_type find_first_not_of(CharT const *s, size_type pos = 0) const // (4)
841  {
842  return find_first_not_of(basic_string_view(s), pos);
843  }
844 
845  // find_last_not_of(), 4x:
846 
847  nssv_constexpr size_type find_last_not_of(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1)
848  {
849  return empty() ? npos
850  : pos >= size()
851  ? find_last_not_of(v, size() - 1)
852  : to_pos(std::find_if(const_reverse_iterator(cbegin() + pos + 1), crend(), not_in_view(v)));
853  }
854 
855  nssv_constexpr size_type find_last_not_of(CharT c, size_type pos = npos) const nssv_noexcept // (2)
856  {
857  return find_last_not_of(basic_string_view(&c, 1), pos);
858  }
859 
860  nssv_constexpr size_type find_last_not_of(CharT const *s, size_type pos, size_type count) const // (3)
861  {
862  return find_last_not_of(basic_string_view(s, count), pos);
863  }
864 
865  nssv_constexpr size_type find_last_not_of(CharT const *s, size_type pos = npos) const // (4)
866  {
867  return find_last_not_of(basic_string_view(s), pos);
868  }
869 
870  // Constants:
871 
872 #if nssv_CPP17_OR_GREATER
873  static nssv_constexpr size_type npos = size_type(-1);
874 #elif nssv_CPP11_OR_GREATER
875  enum : size_type { npos = size_type(-1) };
876 #else
877  enum { npos = size_type(-1) };
878 #endif
879 
880  private:
881  struct not_in_view {
882  const basic_string_view v;
883 
884  nssv_constexpr explicit not_in_view(basic_string_view v) : v(v) {}
885 
886  nssv_constexpr bool operator()(CharT c) const { return npos == v.find_first_of(c); }
887  };
888 
889  nssv_constexpr size_type to_pos(const_iterator it) const { return it == cend() ? npos : size_type(it - cbegin()); }
890 
891  nssv_constexpr size_type to_pos(const_reverse_iterator it) const {
892  return it == crend() ? npos : size_type(crend() - it - 1);
893  }
894 
895  nssv_constexpr const_reference data_at(size_type pos) const {
896 #if nssv_BETWEEN(nssv_COMPILER_GNUC_VERSION, 1, 500)
897  return data_[pos];
898 #else
899  return assert(pos < size()), data_[pos];
900 #endif
901  }
902 
903  private:
904  const_pointer data_;
905  size_type size_;
906 
907  public:
908 #if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
909 
910  template <class Allocator>
911  basic_string_view(std::basic_string<CharT, Traits, Allocator> const &s) nssv_noexcept : data_(s.data()),
912  size_(s.size()) {}
913 
914 #if nssv_HAVE_EXPLICIT_CONVERSION
915 
916  template <class Allocator> explicit operator std::basic_string<CharT, Traits, Allocator>() const {
917  return to_string(Allocator());
918  }
919 
920 #endif // nssv_HAVE_EXPLICIT_CONVERSION
921 
922 #if nssv_CPP11_OR_GREATER
923 
924  template <class Allocator = std::allocator<CharT>>
925  std::basic_string<CharT, Traits, Allocator> to_string(Allocator const &a = Allocator()) const {
926  return std::basic_string<CharT, Traits, Allocator>(begin(), end(), a);
927  }
928 
929 #else
930 
931  std::basic_string<CharT, Traits> to_string() const { return std::basic_string<CharT, Traits>(begin(), end()); }
932 
933  template <class Allocator> std::basic_string<CharT, Traits, Allocator> to_string(Allocator const &a) const {
934  return std::basic_string<CharT, Traits, Allocator>(begin(), end(), a);
935  }
936 
937 #endif // nssv_CPP11_OR_GREATER
938 
939 #endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
940  };
941 
942  //
943  // Non-member functions:
944  //
945 
946  // 24.4.3 Non-member comparison functions:
947  // lexicographically compare two string views (function template):
948 
949  template <class CharT, class Traits>
950  nssv_constexpr bool operator==(basic_string_view<CharT, Traits> lhs,
951  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
952  return lhs.compare(rhs) == 0;
953  }
954 
955  template <class CharT, class Traits>
956  nssv_constexpr bool operator!=(basic_string_view<CharT, Traits> lhs,
957  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
958  return lhs.compare(rhs) != 0;
959  }
960 
961  template <class CharT, class Traits>
962  nssv_constexpr bool operator<(basic_string_view<CharT, Traits> lhs,
963  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
964  return lhs.compare(rhs) < 0;
965  }
966 
967  template <class CharT, class Traits>
968  nssv_constexpr bool operator<=(basic_string_view<CharT, Traits> lhs,
969  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
970  return lhs.compare(rhs) <= 0;
971  }
972 
973  template <class CharT, class Traits>
974  nssv_constexpr bool operator>(basic_string_view<CharT, Traits> lhs,
975  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
976  return lhs.compare(rhs) > 0;
977  }
978 
979  template <class CharT, class Traits>
980  nssv_constexpr bool operator>=(basic_string_view<CharT, Traits> lhs,
981  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
982  return lhs.compare(rhs) >= 0;
983  }
984 
985  // Let S be basic_string_view<CharT, Traits>, and sv be an instance of S.
986  // Implementations shall provide sufficient additional overloads marked
987  // constexpr and noexcept so that an object t with an implicit conversion
988  // to S can be compared according to Table 67.
989 
990 #if !nssv_CPP11_OR_GREATER || nssv_BETWEEN(nssv_COMPILER_MSVC_VERSION, 100, 141)
991 
992  // accomodate for older compilers:
993 
994  // ==
995 
996  template <class CharT, class Traits>
997  nssv_constexpr bool operator==(basic_string_view<CharT, Traits> lhs, char const *rhs) nssv_noexcept {
998  return lhs.compare(rhs) == 0;
999  }
1000 
1001  template <class CharT, class Traits>
1002  nssv_constexpr bool operator==(char const *lhs, basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1003  return rhs.compare(lhs) == 0;
1004  }
1005 
1006  template <class CharT, class Traits>
1007  nssv_constexpr bool operator==(basic_string_view<CharT, Traits> lhs,
1008  std::basic_string<CharT, Traits> rhs) nssv_noexcept {
1009  return lhs.size() == rhs.size() && lhs.compare(rhs) == 0;
1010  }
1011 
1012  template <class CharT, class Traits>
1013  nssv_constexpr bool operator==(std::basic_string<CharT, Traits> rhs,
1014  basic_string_view<CharT, Traits> lhs) nssv_noexcept {
1015  return lhs.size() == rhs.size() && lhs.compare(rhs) == 0;
1016  }
1017 
1018  // !=
1019 
1020  template <class CharT, class Traits>
1021  nssv_constexpr bool operator!=(basic_string_view<CharT, Traits> lhs, char const *rhs) nssv_noexcept {
1022  return lhs.compare(rhs) != 0;
1023  }
1024 
1025  template <class CharT, class Traits>
1026  nssv_constexpr bool operator!=(char const *lhs, basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1027  return rhs.compare(lhs) != 0;
1028  }
1029 
1030  template <class CharT, class Traits>
1031  nssv_constexpr bool operator!=(basic_string_view<CharT, Traits> lhs,
1032  std::basic_string<CharT, Traits> rhs) nssv_noexcept {
1033  return lhs.size() != rhs.size() && lhs.compare(rhs) != 0;
1034  }
1035 
1036  template <class CharT, class Traits>
1037  nssv_constexpr bool operator!=(std::basic_string<CharT, Traits> rhs,
1038  basic_string_view<CharT, Traits> lhs) nssv_noexcept {
1039  return lhs.size() != rhs.size() || rhs.compare(lhs) != 0;
1040  }
1041 
1042  // <
1043 
1044  template <class CharT, class Traits>
1045  nssv_constexpr bool operator<(basic_string_view<CharT, Traits> lhs, char const *rhs) nssv_noexcept {
1046  return lhs.compare(rhs) < 0;
1047  }
1048 
1049  template <class CharT, class Traits>
1050  nssv_constexpr bool operator<(char const *lhs, basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1051  return rhs.compare(lhs) > 0;
1052  }
1053 
1054  template <class CharT, class Traits>
1055  nssv_constexpr bool operator<(basic_string_view<CharT, Traits> lhs,
1056  std::basic_string<CharT, Traits> rhs) nssv_noexcept {
1057  return lhs.compare(rhs) < 0;
1058  }
1059 
1060  template <class CharT, class Traits>
1061  nssv_constexpr bool operator<(std::basic_string<CharT, Traits> rhs,
1062  basic_string_view<CharT, Traits> lhs) nssv_noexcept {
1063  return rhs.compare(lhs) > 0;
1064  }
1065 
1066  // <=
1067 
1068  template <class CharT, class Traits>
1069  nssv_constexpr bool operator<=(basic_string_view<CharT, Traits> lhs, char const *rhs) nssv_noexcept {
1070  return lhs.compare(rhs) <= 0;
1071  }
1072 
1073  template <class CharT, class Traits>
1074  nssv_constexpr bool operator<=(char const *lhs, basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1075  return rhs.compare(lhs) >= 0;
1076  }
1077 
1078  template <class CharT, class Traits>
1079  nssv_constexpr bool operator<=(basic_string_view<CharT, Traits> lhs,
1080  std::basic_string<CharT, Traits> rhs) nssv_noexcept {
1081  return lhs.compare(rhs) <= 0;
1082  }
1083 
1084  template <class CharT, class Traits>
1085  nssv_constexpr bool operator<=(std::basic_string<CharT, Traits> rhs,
1086  basic_string_view<CharT, Traits> lhs) nssv_noexcept {
1087  return rhs.compare(lhs) >= 0;
1088  }
1089 
1090  // >
1091 
1092  template <class CharT, class Traits>
1093  nssv_constexpr bool operator>(basic_string_view<CharT, Traits> lhs, char const *rhs) nssv_noexcept {
1094  return lhs.compare(rhs) > 0;
1095  }
1096 
1097  template <class CharT, class Traits>
1098  nssv_constexpr bool operator>(char const *lhs, basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1099  return rhs.compare(lhs) < 0;
1100  }
1101 
1102  template <class CharT, class Traits>
1103  nssv_constexpr bool operator>(basic_string_view<CharT, Traits> lhs,
1104  std::basic_string<CharT, Traits> rhs) nssv_noexcept {
1105  return lhs.compare(rhs) > 0;
1106  }
1107 
1108  template <class CharT, class Traits>
1109  nssv_constexpr bool operator>(std::basic_string<CharT, Traits> rhs,
1110  basic_string_view<CharT, Traits> lhs) nssv_noexcept {
1111  return rhs.compare(lhs) < 0;
1112  }
1113 
1114  // >=
1115 
1116  template <class CharT, class Traits>
1117  nssv_constexpr bool operator>=(basic_string_view<CharT, Traits> lhs, char const *rhs) nssv_noexcept {
1118  return lhs.compare(rhs) >= 0;
1119  }
1120 
1121  template <class CharT, class Traits>
1122  nssv_constexpr bool operator>=(char const *lhs, basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1123  return rhs.compare(lhs) <= 0;
1124  }
1125 
1126  template <class CharT, class Traits>
1127  nssv_constexpr bool operator>=(basic_string_view<CharT, Traits> lhs,
1128  std::basic_string<CharT, Traits> rhs) nssv_noexcept {
1129  return lhs.compare(rhs) >= 0;
1130  }
1131 
1132  template <class CharT, class Traits>
1133  nssv_constexpr bool operator>=(std::basic_string<CharT, Traits> rhs,
1134  basic_string_view<CharT, Traits> lhs) nssv_noexcept {
1135  return rhs.compare(lhs) <= 0;
1136  }
1137 
1138 #else // newer compilers:
1139 
1140 #define nssv_BASIC_STRING_VIEW_I(T, U) typename std::decay<basic_string_view<T, U>>::type
1141 
1142 #if nssv_BETWEEN(nssv_COMPILER_MSVC_VERSION, 140, 150)
1143 #define nssv_MSVC_ORDER(x) , int = x
1144 #else
1145 #define nssv_MSVC_ORDER(x) /*, int=x*/
1146 #endif
1147 
1148  // ==
1149 
1150  template <class CharT, class Traits nssv_MSVC_ORDER(1)>
1151  nssv_constexpr bool operator==(basic_string_view<CharT, Traits> lhs,
1152  nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept {
1153  return lhs.compare(rhs) == 0;
1154  }
1155 
1156  template <class CharT, class Traits nssv_MSVC_ORDER(2)>
1157  nssv_constexpr bool operator==(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,
1158  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1159  return lhs.size() == rhs.size() && lhs.compare(rhs) == 0;
1160  }
1161 
1162  // !=
1163 
1164  template <class CharT, class Traits nssv_MSVC_ORDER(1)>
1165  nssv_constexpr bool operator!=(basic_string_view<CharT, Traits> lhs,
1166  nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept {
1167  return lhs.size() != rhs.size() || lhs.compare(rhs) != 0;
1168  }
1169 
1170  template <class CharT, class Traits nssv_MSVC_ORDER(2)>
1171  nssv_constexpr bool operator!=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,
1172  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1173  return lhs.compare(rhs) != 0;
1174  }
1175 
1176  // <
1177 
1178  template <class CharT, class Traits nssv_MSVC_ORDER(1)>
1179  nssv_constexpr bool operator<(basic_string_view<CharT, Traits> lhs,
1180  nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept {
1181  return lhs.compare(rhs) < 0;
1182  }
1183 
1184  template <class CharT, class Traits nssv_MSVC_ORDER(2)>
1185  nssv_constexpr bool operator<(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,
1186  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1187  return lhs.compare(rhs) < 0;
1188  }
1189 
1190  // <=
1191 
1192  template <class CharT, class Traits nssv_MSVC_ORDER(1)>
1193  nssv_constexpr bool operator<=(basic_string_view<CharT, Traits> lhs,
1194  nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept {
1195  return lhs.compare(rhs) <= 0;
1196  }
1197 
1198  template <class CharT, class Traits nssv_MSVC_ORDER(2)>
1199  nssv_constexpr bool operator<=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,
1200  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1201  return lhs.compare(rhs) <= 0;
1202  }
1203 
1204  // >
1205 
1206  template <class CharT, class Traits nssv_MSVC_ORDER(1)>
1207  nssv_constexpr bool operator>(basic_string_view<CharT, Traits> lhs,
1208  nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept {
1209  return lhs.compare(rhs) > 0;
1210  }
1211 
1212  template <class CharT, class Traits nssv_MSVC_ORDER(2)>
1213  nssv_constexpr bool operator>(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,
1214  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1215  return lhs.compare(rhs) > 0;
1216  }
1217 
1218  // >=
1219 
1220  template <class CharT, class Traits nssv_MSVC_ORDER(1)>
1221  nssv_constexpr bool operator>=(basic_string_view<CharT, Traits> lhs,
1222  nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept {
1223  return lhs.compare(rhs) >= 0;
1224  }
1225 
1226  template <class CharT, class Traits nssv_MSVC_ORDER(2)>
1227  nssv_constexpr bool operator>=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,
1228  basic_string_view<CharT, Traits> rhs) nssv_noexcept {
1229  return lhs.compare(rhs) >= 0;
1230  }
1231 
1232 #undef nssv_MSVC_ORDER
1233 #undef nssv_BASIC_STRING_VIEW_I
1234 
1235 #endif // compiler-dependent approach to comparisons
1236 
1237  // 24.4.4 Inserters and extractors:
1238 
1239  namespace detail {
1240 
1241  template <class Stream> void write_padding(Stream &os, std::streamsize n) {
1242  for (std::streamsize i = 0; i < n; ++i)
1243  os.rdbuf()->sputc(os.fill());
1244  }
1245 
1246  template <class Stream, class View> Stream &write_to_stream(Stream &os, View const &sv) {
1247  typename Stream::sentry sentry(os);
1248 
1249  if (!os)
1250  return os;
1251 
1252  const std::streamsize length = static_cast<std::streamsize>(sv.length());
1253 
1254  // Whether, and how, to pad:
1255  const bool pad = (length < os.width());
1256  const bool left_pad = pad && (os.flags() & std::ios_base::adjustfield) == std::ios_base::right;
1257 
1258  if (left_pad)
1259  write_padding(os, os.width() - length);
1260 
1261  // Write span characters:
1262  os.rdbuf()->sputn(sv.begin(), length);
1263 
1264  if (pad && !left_pad)
1265  write_padding(os, os.width() - length);
1266 
1267  // Reset output stream width:
1268  os.width(0);
1269 
1270  return os;
1271  }
1272 
1273  } // namespace detail
1274 
1275  template <class CharT, class Traits>
1276  std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &os,
1277  basic_string_view<CharT, Traits> sv) {
1278  return detail::write_to_stream(os, sv);
1279  }
1280 
1281  // Several typedefs for common character types are provided:
1282 
1283  typedef basic_string_view<char> string_view;
1284  typedef basic_string_view<wchar_t> wstring_view;
1285 #if nssv_HAVE_WCHAR16_T
1286  typedef basic_string_view<char16_t> u16string_view;
1287  typedef basic_string_view<char32_t> u32string_view;
1288 #endif
1289 
1290  } // namespace sv_lite
1291 } // namespace nonstd::sv_lite
1292 
1293 //
1294 // 24.4.6 Suffix for basic_string_view literals:
1295 //
1296 
1297 #if nssv_HAVE_USER_DEFINED_LITERALS
1298 
1299 namespace nonstd {
1300 nssv_inline_ns namespace literals {
1301  nssv_inline_ns namespace string_view_literals {
1302 
1303 #if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS
1304 
1305  nssv_constexpr nonstd::sv_lite::string_view operator"" sv(const char *str, size_t len) nssv_noexcept // (1)
1306  {
1307  return nonstd::sv_lite::string_view {str, len};
1308  }
1309 
1310  nssv_constexpr nonstd::sv_lite::u16string_view operator"" sv(const char16_t *str, size_t len) nssv_noexcept // (2)
1311  {
1312  return nonstd::sv_lite::u16string_view {str, len};
1313  }
1314 
1315  nssv_constexpr nonstd::sv_lite::u32string_view operator"" sv(const char32_t *str, size_t len) nssv_noexcept // (3)
1316  {
1317  return nonstd::sv_lite::u32string_view {str, len};
1318  }
1319 
1320  nssv_constexpr nonstd::sv_lite::wstring_view operator"" sv(const wchar_t *str, size_t len) nssv_noexcept // (4)
1321  {
1322  return nonstd::sv_lite::wstring_view {str, len};
1323  }
1324 
1325 #endif // nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS
1326 
1327 #if nssv_CONFIG_USR_SV_OPERATOR
1328 
1329  nssv_constexpr nonstd::sv_lite::string_view operator"" _sv(const char *str, size_t len) nssv_noexcept // (1)
1330  {
1331  return nonstd::sv_lite::string_view {str, len};
1332  }
1333 
1334  nssv_constexpr nonstd::sv_lite::u16string_view operator"" _sv(const char16_t *str, size_t len) nssv_noexcept // (2)
1335  {
1336  return nonstd::sv_lite::u16string_view {str, len};
1337  }
1338 
1339  nssv_constexpr nonstd::sv_lite::u32string_view operator"" _sv(const char32_t *str, size_t len) nssv_noexcept // (3)
1340  {
1341  return nonstd::sv_lite::u32string_view {str, len};
1342  }
1343 
1344  nssv_constexpr nonstd::sv_lite::wstring_view operator"" _sv(const wchar_t *str, size_t len) nssv_noexcept // (4)
1345  {
1346  return nonstd::sv_lite::wstring_view {str, len};
1347  }
1348 
1349 #endif // nssv_CONFIG_USR_SV_OPERATOR
1350  }
1351 }
1352 } // namespace nonstd
1353 
1354 #endif
1355 
1356 //
1357 // Extensions for std::string:
1358 //
1359 
1360 #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
1361 
1362 namespace nonstd {
1363 namespace sv_lite {
1364 
1365 // Exclude MSVC 14 (19.00): it yields ambiguous to_string():
1366 
1367 #if nssv_CPP11_OR_GREATER && nssv_COMPILER_MSVC_VERSION != 140
1368 
1369 template <class CharT, class Traits, class Allocator = std::allocator<CharT>>
1370 std::basic_string<CharT, Traits, Allocator> to_string(basic_string_view<CharT, Traits> v,
1371  Allocator const &a = Allocator()) {
1372  return std::basic_string<CharT, Traits, Allocator>(v.begin(), v.end(), a);
1373 }
1374 
1375 #else
1376 
1377 template <class CharT, class Traits> std::basic_string<CharT, Traits> to_string(basic_string_view<CharT, Traits> v) {
1378  return std::basic_string<CharT, Traits>(v.begin(), v.end());
1379 }
1380 
1381 template <class CharT, class Traits, class Allocator>
1382 std::basic_string<CharT, Traits, Allocator> to_string(basic_string_view<CharT, Traits> v, Allocator const &a) {
1383  return std::basic_string<CharT, Traits, Allocator>(v.begin(), v.end(), a);
1384 }
1385 
1386 #endif // nssv_CPP11_OR_GREATER
1387 
1388 template <class CharT, class Traits, class Allocator>
1389 basic_string_view<CharT, Traits> to_string_view(std::basic_string<CharT, Traits, Allocator> const &s) {
1390  return basic_string_view<CharT, Traits>(s.data(), s.size());
1391 }
1392 
1393 } // namespace sv_lite
1394 } // namespace nonstd
1395 
1396 #endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
1397 
1398 //
1399 // make types and algorithms available in namespace nonstd:
1400 //
1401 
1402 namespace nonstd {
1403 
1404 using sv_lite::basic_string_view;
1405 using sv_lite::string_view;
1406 using sv_lite::wstring_view;
1407 
1408 #if nssv_HAVE_WCHAR16_T
1409 using sv_lite::u16string_view;
1410 #endif
1411 #if nssv_HAVE_WCHAR32_T
1412 using sv_lite::u32string_view;
1413 #endif
1414 
1415 // literal "sv"
1416 
1417 using sv_lite::operator==;
1418 using sv_lite::operator!=;
1419 using sv_lite::operator<;
1420 using sv_lite::operator<=;
1421 using sv_lite::operator>;
1422 using sv_lite::operator>=;
1423 
1424 using sv_lite::operator<<;
1425 
1426 #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
1427 using sv_lite::to_string;
1429 #endif
1430 
1431 } // namespace nonstd
1432 
1433 // 24.4.5 Hash support (C++11):
1434 
1435 // Note: The hash value of a string view object is equal to the hash value of
1436 // the corresponding string object.
1437 
1438 #if nssv_HAVE_STD_HASH
1439 
1440 #include <functional>
1441 
1442 namespace std {
1443 
1444 template <> struct hash<nonstd::string_view> {
1445 public:
1446  std::size_t operator()(nonstd::string_view v) const nssv_noexcept {
1447  return std::hash<std::string>()(std::string(v.data(), v.size()));
1448  }
1449 };
1450 
1451 template <> struct hash<nonstd::wstring_view> {
1452 public:
1453  std::size_t operator()(nonstd::wstring_view v) const nssv_noexcept {
1454  return std::hash<std::wstring>()(std::wstring(v.data(), v.size()));
1455  }
1456 };
1457 
1458 template <> struct hash<nonstd::u16string_view> {
1459 public:
1460  std::size_t operator()(nonstd::u16string_view v) const nssv_noexcept {
1461  return std::hash<std::u16string>()(std::u16string(v.data(), v.size()));
1462  }
1463 };
1464 
1465 template <> struct hash<nonstd::u32string_view> {
1466 public:
1467  std::size_t operator()(nonstd::u32string_view v) const nssv_noexcept {
1468  return std::hash<std::u32string>()(std::u32string(v.data(), v.size()));
1469  }
1470 };
1471 
1472 } // namespace std
1473 
1474 #endif // nssv_HAVE_STD_HASH
1475 
1477 
1478 #endif // nssv_HAVE_STD_STRING_VIEW
1479 #endif // NONSTD_SV_LITE_H_INCLUDED
1480 
1481 
1482 namespace inja {
1483 
1487 struct LexerConfig {
1488  std::string statement_open {"{%"};
1489  std::string statement_open_no_lstrip {"{%+"};
1490  std::string statement_open_force_lstrip {"{%-"};
1491  std::string statement_close {"%}"};
1492  std::string statement_close_force_rstrip {"-%}"};
1493  std::string line_statement {"##"};
1494  std::string expression_open {"{{"};
1495  std::string expression_open_force_lstrip {"{{-"};
1496  std::string expression_close {"}}"};
1497  std::string expression_close_force_rstrip {"-}}"};
1498  std::string comment_open {"{#"};
1499  std::string comment_open_force_lstrip {"{#-"};
1500  std::string comment_close {"#}"};
1501  std::string comment_close_force_rstrip {"-#}"};
1502  std::string open_chars {"#{"};
1503 
1504  bool trim_blocks {false};
1505  bool lstrip_blocks {false};
1506 
1507  void update_open_chars() {
1508  open_chars = "";
1509  if (open_chars.find(line_statement[0]) == std::string::npos) {
1510  open_chars += line_statement[0];
1511  }
1512  if (open_chars.find(statement_open[0]) == std::string::npos) {
1513  open_chars += statement_open[0];
1514  }
1515  if (open_chars.find(statement_open_no_lstrip[0]) == std::string::npos) {
1516  open_chars += statement_open_no_lstrip[0];
1517  }
1518  if (open_chars.find(statement_open_force_lstrip[0]) == std::string::npos) {
1519  open_chars += statement_open_force_lstrip[0];
1520  }
1521  if (open_chars.find(expression_open[0]) == std::string::npos) {
1522  open_chars += expression_open[0];
1523  }
1524  if (open_chars.find(expression_open_force_lstrip[0]) == std::string::npos) {
1525  open_chars += expression_open_force_lstrip[0];
1526  }
1527  if (open_chars.find(comment_open[0]) == std::string::npos) {
1528  open_chars += comment_open[0];
1529  }
1530  if (open_chars.find(comment_open_force_lstrip[0]) == std::string::npos) {
1531  open_chars += comment_open_force_lstrip[0];
1532  }
1533  }
1534 };
1535 
1539 struct ParserConfig {
1540  bool search_included_templates_in_files {true};
1541 };
1542 
1546 struct RenderConfig {
1547  bool throw_at_missing_includes {true};
1548 };
1549 
1550 } // namespace inja
1551 
1552 #endif // INCLUDE_INJA_CONFIG_HPP_
1553 
1554 // #include "function_storage.hpp"
1555 #ifndef INCLUDE_INJA_FUNCTION_STORAGE_HPP_
1556 #define INCLUDE_INJA_FUNCTION_STORAGE_HPP_
1557 
1558 #include <vector>
1559 
1560 // #include "string_view.hpp"
1561 
1562 
1563 namespace inja {
1564 
1566 
1567 using Arguments = std::vector<const json *>;
1568 using CallbackFunction = std::function<json(Arguments &args)>;
1569 using VoidCallbackFunction = std::function<void(Arguments &args)>;
1570 
1575 public:
1576  enum class Operation {
1577  Not,
1578  And,
1579  Or,
1580  In,
1581  Equal,
1582  NotEqual,
1583  Greater,
1584  GreaterEqual,
1585  Less,
1586  LessEqual,
1587  Add,
1588  Subtract,
1589  Multiplication,
1590  Division,
1591  Power,
1592  Modulo,
1593  AtId,
1594  At,
1595  Default,
1596  DivisibleBy,
1597  Even,
1598  Exists,
1599  ExistsInObject,
1600  First,
1601  Float,
1602  Int,
1603  IsArray,
1604  IsBoolean,
1605  IsFloat,
1606  IsInteger,
1607  IsNumber,
1608  IsObject,
1609  IsString,
1610  Last,
1611  Length,
1612  Lower,
1613  Max,
1614  Min,
1615  Odd,
1616  Range,
1617  Round,
1618  Sort,
1619  Upper,
1620  Super,
1621  Join,
1622  Callback,
1623  ParenLeft,
1624  ParenRight,
1625  None,
1626  };
1627 
1628  struct FunctionData {
1629  explicit FunctionData(const Operation &op, const CallbackFunction &cb = CallbackFunction{}) : operation(op), callback(cb) {}
1632  };
1633 
1634 private:
1635  const int VARIADIC {-1};
1636 
1637  std::map<std::pair<std::string, int>, FunctionData> function_storage = {
1638  {std::make_pair("at", 2), FunctionData { Operation::At }},
1639  {std::make_pair("default", 2), FunctionData { Operation::Default }},
1640  {std::make_pair("divisibleBy", 2), FunctionData { Operation::DivisibleBy }},
1641  {std::make_pair("even", 1), FunctionData { Operation::Even }},
1642  {std::make_pair("exists", 1), FunctionData { Operation::Exists }},
1643  {std::make_pair("existsIn", 2), FunctionData { Operation::ExistsInObject }},
1644  {std::make_pair("first", 1), FunctionData { Operation::First }},
1645  {std::make_pair("float", 1), FunctionData { Operation::Float }},
1646  {std::make_pair("int", 1), FunctionData { Operation::Int }},
1647  {std::make_pair("isArray", 1), FunctionData { Operation::IsArray }},
1648  {std::make_pair("isBoolean", 1), FunctionData { Operation::IsBoolean }},
1649  {std::make_pair("isFloat", 1), FunctionData { Operation::IsFloat }},
1650  {std::make_pair("isInteger", 1), FunctionData { Operation::IsInteger }},
1651  {std::make_pair("isNumber", 1), FunctionData { Operation::IsNumber }},
1652  {std::make_pair("isObject", 1), FunctionData { Operation::IsObject }},
1653  {std::make_pair("isString", 1), FunctionData { Operation::IsString }},
1654  {std::make_pair("last", 1), FunctionData { Operation::Last }},
1655  {std::make_pair("length", 1), FunctionData { Operation::Length }},
1656  {std::make_pair("lower", 1), FunctionData { Operation::Lower }},
1657  {std::make_pair("max", 1), FunctionData { Operation::Max }},
1658  {std::make_pair("min", 1), FunctionData { Operation::Min }},
1659  {std::make_pair("odd", 1), FunctionData { Operation::Odd }},
1660  {std::make_pair("range", 1), FunctionData { Operation::Range }},
1661  {std::make_pair("round", 2), FunctionData { Operation::Round }},
1662  {std::make_pair("sort", 1), FunctionData { Operation::Sort }},
1663  {std::make_pair("upper", 1), FunctionData { Operation::Upper }},
1664  {std::make_pair("super", 0), FunctionData { Operation::Super }},
1665  {std::make_pair("super", 1), FunctionData { Operation::Super }},
1666  {std::make_pair("join", 2), FunctionData { Operation::Join }},
1667  };
1668 
1669 public:
1670  void add_builtin(nonstd::string_view name, int num_args, Operation op) {
1671  function_storage.emplace(std::make_pair(static_cast<std::string>(name), num_args), FunctionData { op });
1672  }
1673 
1674  void add_callback(nonstd::string_view name, int num_args, const CallbackFunction &callback) {
1675  function_storage.emplace(std::make_pair(static_cast<std::string>(name), num_args), FunctionData { Operation::Callback, callback });
1676  }
1677 
1678  FunctionData find_function(nonstd::string_view name, int num_args) const {
1679  auto it = function_storage.find(std::make_pair(static_cast<std::string>(name), num_args));
1680  if (it != function_storage.end()) {
1681  return it->second;
1682 
1683  // Find variadic function
1684  } else if (num_args > 0) {
1685  it = function_storage.find(std::make_pair(static_cast<std::string>(name), VARIADIC));
1686  if (it != function_storage.end()) {
1687  return it->second;
1688  }
1689  }
1690 
1691  return FunctionData { Operation::None };
1692  }
1693 };
1694 
1695 } // namespace inja
1696 
1697 #endif // INCLUDE_INJA_FUNCTION_STORAGE_HPP_
1698 
1699 // #include "parser.hpp"
1700 #ifndef INCLUDE_INJA_PARSER_HPP_
1701 #define INCLUDE_INJA_PARSER_HPP_
1702 
1703 #include <limits>
1704 #include <stack>
1705 #include <string>
1706 #include <utility>
1707 #include <queue>
1708 #include <vector>
1709 
1710 // #include "config.hpp"
1711 
1712 // #include "exceptions.hpp"
1713 #ifndef INCLUDE_INJA_EXCEPTIONS_HPP_
1714 #define INCLUDE_INJA_EXCEPTIONS_HPP_
1715 
1716 #include <stdexcept>
1717 #include <string>
1718 
1719 namespace inja {
1720 
1722  size_t line;
1723  size_t column;
1724 };
1725 
1726 struct InjaError : public std::runtime_error {
1727  const std::string type;
1728  const std::string message;
1729 
1731 
1732  explicit InjaError(const std::string &type, const std::string &message)
1733  : std::runtime_error("[inja.exception." + type + "] " + message), type(type), message(message), location({0, 0}) {}
1734 
1735  explicit InjaError(const std::string &type, const std::string &message, SourceLocation location)
1736  : std::runtime_error("[inja.exception." + type + "] (at " + std::to_string(location.line) + ":" +
1737  std::to_string(location.column) + ") " + message),
1739 };
1740 
1741 struct ParserError : public InjaError {
1742  explicit ParserError(const std::string &message, SourceLocation location) : InjaError("parser_error", message, location) {}
1743 };
1744 
1745 struct RenderError : public InjaError {
1746  explicit RenderError(const std::string &message, SourceLocation location) : InjaError("render_error", message, location) {}
1747 };
1748 
1749 struct FileError : public InjaError {
1750  explicit FileError(const std::string &message) : InjaError("file_error", message) {}
1751  explicit FileError(const std::string &message, SourceLocation location) : InjaError("file_error", message, location) {}
1752 };
1753 
1754 struct JsonError : public InjaError {
1755  explicit JsonError(const std::string &message, SourceLocation location) : InjaError("json_error", message, location) {}
1756 };
1757 
1758 } // namespace inja
1759 
1760 #endif // INCLUDE_INJA_EXCEPTIONS_HPP_
1761 
1762 // #include "function_storage.hpp"
1763 
1764 // #include "lexer.hpp"
1765 #ifndef INCLUDE_INJA_LEXER_HPP_
1766 #define INCLUDE_INJA_LEXER_HPP_
1767 
1768 #include <cctype>
1769 #include <locale>
1770 
1771 // #include "config.hpp"
1772 
1773 // #include "token.hpp"
1774 #ifndef INCLUDE_INJA_TOKEN_HPP_
1775 #define INCLUDE_INJA_TOKEN_HPP_
1776 
1777 #include <string>
1778 
1779 // #include "string_view.hpp"
1780 
1781 
1782 namespace inja {
1783 
1787 struct Token {
1788  enum class Kind {
1789  Text,
1790  ExpressionOpen, // {{
1791  ExpressionClose, // }}
1792  LineStatementOpen, // ##
1793  LineStatementClose, // \n
1794  StatementOpen, // {%
1795  StatementClose, // %}
1796  CommentOpen, // {#
1797  CommentClose, // #}
1798  Id, // this, this.foo
1799  Number, // 1, 2, -1, 5.2, -5.3
1800  String, // "this"
1801  Plus, // +
1802  Minus, // -
1803  Times, // *
1804  Slash, // /
1805  Percent, // %
1806  Power, // ^
1807  Comma, // ,
1808  Dot, // .
1809  Colon, // :
1810  LeftParen, // (
1811  RightParen, // )
1812  LeftBracket, // [
1813  RightBracket, // ]
1814  LeftBrace, // {
1815  RightBrace, // }
1816  Equal, // ==
1817  NotEqual, // !=
1818  GreaterThan, // >
1819  GreaterEqual, // >=
1820  LessThan, // <
1821  LessEqual, // <=
1822  Unknown,
1823  Eof,
1824  };
1825 
1826  Kind kind {Kind::Unknown};
1827  nonstd::string_view text;
1828 
1829  explicit constexpr Token() = default;
1830  explicit constexpr Token(Kind kind, nonstd::string_view text) : kind(kind), text(text) {}
1831 
1832  std::string describe() const {
1833  switch (kind) {
1834  case Kind::Text:
1835  return "<text>";
1836  case Kind::LineStatementClose:
1837  return "<eol>";
1838  case Kind::Eof:
1839  return "<eof>";
1840  default:
1841  return static_cast<std::string>(text);
1842  }
1843  }
1844 };
1845 
1846 } // namespace inja
1847 
1848 #endif // INCLUDE_INJA_TOKEN_HPP_
1849 
1850 // #include "utils.hpp"
1851 #ifndef INCLUDE_INJA_UTILS_HPP_
1852 #define INCLUDE_INJA_UTILS_HPP_
1853 
1854 #include <algorithm>
1855 #include <fstream>
1856 #include <string>
1857 #include <utility>
1858 
1859 // #include "exceptions.hpp"
1860 
1861 // #include "string_view.hpp"
1862 
1863 
1864 namespace inja {
1865 
1866 inline void open_file_or_throw(const std::string &path, std::ifstream &file) {
1867  file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
1868 #ifndef INJA_NOEXCEPTION
1869  try {
1870  file.open(path);
1871  } catch (const std::ios_base::failure & /*e*/) {
1872  INJA_THROW(FileError("failed accessing file at '" + path + "'"));
1873  }
1874 #else
1875  file.open(path);
1876 #endif
1877 }
1878 
1879 namespace string_view {
1880 inline nonstd::string_view slice(nonstd::string_view view, size_t start, size_t end) {
1881  start = std::min(start, view.size());
1882  end = std::min(std::max(start, end), view.size());
1883  return view.substr(start, end - start);
1884 }
1885 
1886 inline std::pair<nonstd::string_view, nonstd::string_view> split(nonstd::string_view view, char Separator) {
1887  size_t idx = view.find(Separator);
1888  if (idx == nonstd::string_view::npos) {
1889  return std::make_pair(view, nonstd::string_view());
1890  }
1891  return std::make_pair(slice(view, 0, idx), slice(view, idx + 1, nonstd::string_view::npos));
1892 }
1893 
1894 inline bool starts_with(nonstd::string_view view, nonstd::string_view prefix) {
1895  return (view.size() >= prefix.size() && view.compare(0, prefix.size(), prefix) == 0);
1896 }
1897 } // namespace string_view
1898 
1899 inline SourceLocation get_source_location(nonstd::string_view content, size_t pos) {
1900  // Get line and offset position (starts at 1:1)
1901  auto sliced = string_view::slice(content, 0, pos);
1902  std::size_t last_newline = sliced.rfind("\n");
1903 
1904  if (last_newline == nonstd::string_view::npos) {
1905  return {1, sliced.length() + 1};
1906  }
1907 
1908  // Count newlines
1909  size_t count_lines = 0;
1910  size_t search_start = 0;
1911  while (search_start <= sliced.size()) {
1912  search_start = sliced.find("\n", search_start) + 1;
1913  if (search_start == 0) {
1914  break;
1915  }
1916  count_lines += 1;
1917  }
1918 
1919  return {count_lines + 1, sliced.length() - last_newline};
1920 }
1921 
1922 inline void replace_substring(std::string& s, const std::string& f,
1923  const std::string& t)
1924 {
1925  if (f.empty()) return;
1926  for (auto pos = s.find(f); // find first occurrence of f
1927  pos != std::string::npos; // make sure f was found
1928  s.replace(pos, f.size(), t), // replace with t, and
1929  pos = s.find(f, pos + t.size())) // find next occurrence of f
1930  {}
1931 }
1932 
1933 } // namespace inja
1934 
1935 #endif // INCLUDE_INJA_UTILS_HPP_
1936 
1937 
1938 namespace inja {
1939 
1943 class Lexer {
1944  enum class State {
1945  Text,
1946  ExpressionStart,
1947  ExpressionStartForceLstrip,
1948  ExpressionBody,
1949  LineStart,
1950  LineBody,
1951  StatementStart,
1952  StatementStartNoLstrip,
1953  StatementStartForceLstrip,
1954  StatementBody,
1955  CommentStart,
1956  CommentStartForceLstrip,
1957  CommentBody,
1958  };
1959 
1960  enum class MinusState {
1961  Operator,
1962  Number,
1963  };
1964 
1965  const LexerConfig &config;
1966 
1969  nonstd::string_view m_in;
1970  size_t tok_start;
1971  size_t pos;
1972 
1973 
1974  Token scan_body(nonstd::string_view close, Token::Kind closeKind, nonstd::string_view close_trim = nonstd::string_view(), bool trim = false) {
1975  again:
1976  // skip whitespace (except for \n as it might be a close)
1977  if (tok_start >= m_in.size()) {
1978  return make_token(Token::Kind::Eof);
1979  }
1980  const char ch = m_in[tok_start];
1981  if (ch == ' ' || ch == '\t' || ch == '\r') {
1982  tok_start += 1;
1983  goto again;
1984  }
1985 
1986  // check for close
1987  if (!close_trim.empty() && inja::string_view::starts_with(m_in.substr(tok_start), close_trim)) {
1988  state = State::Text;
1989  pos = tok_start + close_trim.size();
1990  const Token tok = make_token(closeKind);
1991  skip_whitespaces_and_newlines();
1992  return tok;
1993  }
1994 
1995  if (inja::string_view::starts_with(m_in.substr(tok_start), close)) {
1996  state = State::Text;
1997  pos = tok_start + close.size();
1998  const Token tok = make_token(closeKind);
1999  if (trim) {
2000  skip_whitespaces_and_first_newline();
2001  }
2002  return tok;
2003  }
2004 
2005  // skip \n
2006  if (ch == '\n') {
2007  tok_start += 1;
2008  goto again;
2009  }
2010 
2011  pos = tok_start + 1;
2012  if (std::isalpha(ch)) {
2013  minus_state = MinusState::Operator;
2014  return scan_id();
2015  }
2016 
2017  const MinusState current_minus_state = minus_state;
2018  if (minus_state == MinusState::Operator) {
2019  minus_state = MinusState::Number;
2020  }
2021 
2022  switch (ch) {
2023  case '+':
2024  return make_token(Token::Kind::Plus);
2025  case '-':
2026  if (current_minus_state == MinusState::Operator) {
2027  return make_token(Token::Kind::Minus);
2028  }
2029  return scan_number();
2030  case '*':
2031  return make_token(Token::Kind::Times);
2032  case '/':
2033  return make_token(Token::Kind::Slash);
2034  case '^':
2035  return make_token(Token::Kind::Power);
2036  case '%':
2037  return make_token(Token::Kind::Percent);
2038  case '.':
2039  return make_token(Token::Kind::Dot);
2040  case ',':
2041  return make_token(Token::Kind::Comma);
2042  case ':':
2043  return make_token(Token::Kind::Colon);
2044  case '(':
2045  return make_token(Token::Kind::LeftParen);
2046  case ')':
2047  minus_state = MinusState::Operator;
2048  return make_token(Token::Kind::RightParen);
2049  case '[':
2050  return make_token(Token::Kind::LeftBracket);
2051  case ']':
2052  minus_state = MinusState::Operator;
2053  return make_token(Token::Kind::RightBracket);
2054  case '{':
2055  return make_token(Token::Kind::LeftBrace);
2056  case '}':
2057  minus_state = MinusState::Operator;
2058  return make_token(Token::Kind::RightBrace);
2059  case '>':
2060  if (pos < m_in.size() && m_in[pos] == '=') {
2061  pos += 1;
2062  return make_token(Token::Kind::GreaterEqual);
2063  }
2064  return make_token(Token::Kind::GreaterThan);
2065  case '<':
2066  if (pos < m_in.size() && m_in[pos] == '=') {
2067  pos += 1;
2068  return make_token(Token::Kind::LessEqual);
2069  }
2070  return make_token(Token::Kind::LessThan);
2071  case '=':
2072  if (pos < m_in.size() && m_in[pos] == '=') {
2073  pos += 1;
2074  return make_token(Token::Kind::Equal);
2075  }
2076  return make_token(Token::Kind::Unknown);
2077  case '!':
2078  if (pos < m_in.size() && m_in[pos] == '=') {
2079  pos += 1;
2080  return make_token(Token::Kind::NotEqual);
2081  }
2082  return make_token(Token::Kind::Unknown);
2083  case '\"':
2084  return scan_string();
2085  case '0':
2086  case '1':
2087  case '2':
2088  case '3':
2089  case '4':
2090  case '5':
2091  case '6':
2092  case '7':
2093  case '8':
2094  case '9':
2095  minus_state = MinusState::Operator;
2096  return scan_number();
2097  case '_':
2098  case '@':
2099  case '$':
2100  minus_state = MinusState::Operator;
2101  return scan_id();
2102  default:
2103  return make_token(Token::Kind::Unknown);
2104  }
2105  }
2106 
2108  for (;;) {
2109  if (pos >= m_in.size()) {
2110  break;
2111  }
2112  const char ch = m_in[pos];
2113  if (!std::isalnum(ch) && ch != '.' && ch != '/' && ch != '_' && ch != '-') {
2114  break;
2115  }
2116  pos += 1;
2117  }
2118  return make_token(Token::Kind::Id);
2119  }
2120 
2122  for (;;) {
2123  if (pos >= m_in.size()) {
2124  break;
2125  }
2126  const char ch = m_in[pos];
2127  // be very permissive in lexer (we'll catch errors when conversion happens)
2128  if (!std::isdigit(ch) && ch != '.' && ch != 'e' && ch != 'E' && ch != '+' && ch != '-') {
2129  break;
2130  }
2131  pos += 1;
2132  }
2133  return make_token(Token::Kind::Number);
2134  }
2135 
2137  bool escape {false};
2138  for (;;) {
2139  if (pos >= m_in.size()) {
2140  break;
2141  }
2142  const char ch = m_in[pos++];
2143  if (ch == '\\') {
2144  escape = true;
2145  } else if (!escape && ch == m_in[tok_start]) {
2146  break;
2147  } else {
2148  escape = false;
2149  }
2150  }
2151  return make_token(Token::Kind::String);
2152  }
2153 
2154  Token make_token(Token::Kind kind) const { return Token(kind, string_view::slice(m_in, tok_start, pos)); }
2155 
2157  if (pos < m_in.size()) {
2158  while (pos < m_in.size() && (m_in[pos] == ' ' || m_in[pos] == '\t' || m_in[pos] == '\n' || m_in[pos] == '\r')) {
2159  pos += 1;
2160  }
2161  }
2162  }
2163 
2165  if (pos < m_in.size()) {
2166  while (pos < m_in.size() && (m_in[pos] == ' ' || m_in[pos] == '\t')) {
2167  pos += 1;
2168  }
2169  }
2170 
2171  if (pos < m_in.size()) {
2172  const char ch = m_in[pos];
2173  if (ch == '\n') {
2174  pos += 1;
2175  } else if (ch == '\r') {
2176  pos += 1;
2177  if (pos < m_in.size() && m_in[pos] == '\n') {
2178  pos += 1;
2179  }
2180  }
2181  }
2182  }
2183 
2184  static nonstd::string_view clear_final_line_if_whitespace(nonstd::string_view text) {
2185  nonstd::string_view result = text;
2186  while (!result.empty()) {
2187  const char ch = result.back();
2188  if (ch == ' ' || ch == '\t') {
2189  result.remove_suffix(1);
2190  } else if (ch == '\n' || ch == '\r') {
2191  break;
2192  } else {
2193  return text;
2194  }
2195  }
2196  return result;
2197  }
2198 
2199 public:
2200  explicit Lexer(const LexerConfig &config) : config(config), state(State::Text), minus_state(MinusState::Number) {}
2201 
2203  return get_source_location(m_in, tok_start);
2204  }
2205 
2206  void start(nonstd::string_view input) {
2207  m_in = input;
2208  tok_start = 0;
2209  pos = 0;
2210  state = State::Text;
2211  minus_state = MinusState::Number;
2212 
2213  // Consume byte order mark (BOM) for UTF-8
2214  if (inja::string_view::starts_with(m_in, "\xEF\xBB\xBF")) {
2215  m_in = m_in.substr(3);
2216  }
2217  }
2218 
2220  tok_start = pos;
2221 
2222  again:
2223  if (tok_start >= m_in.size()) {
2224  return make_token(Token::Kind::Eof);
2225  }
2226 
2227  switch (state) {
2228  default:
2229  case State::Text: {
2230  // fast-scan to first open character
2231  const size_t open_start = m_in.substr(pos).find_first_of(config.open_chars);
2232  if (open_start == nonstd::string_view::npos) {
2233  // didn't find open, return remaining text as text token
2234  pos = m_in.size();
2235  return make_token(Token::Kind::Text);
2236  }
2237  pos += open_start;
2238 
2239  // try to match one of the opening sequences, and get the close
2240  nonstd::string_view open_str = m_in.substr(pos);
2241  bool must_lstrip = false;
2242  if (inja::string_view::starts_with(open_str, config.expression_open)) {
2243  if (inja::string_view::starts_with(open_str, config.expression_open_force_lstrip)) {
2244  state = State::ExpressionStartForceLstrip;
2245  must_lstrip = true;
2246  } else {
2247  state = State::ExpressionStart;
2248  }
2249  } else if (inja::string_view::starts_with(open_str, config.statement_open)) {
2250  if (inja::string_view::starts_with(open_str, config.statement_open_no_lstrip)) {
2251  state = State::StatementStartNoLstrip;
2252  } else if (inja::string_view::starts_with(open_str, config.statement_open_force_lstrip )) {
2253  state = State::StatementStartForceLstrip;
2254  must_lstrip = true;
2255  } else {
2256  state = State::StatementStart;
2257  must_lstrip = config.lstrip_blocks;
2258  }
2259  } else if (inja::string_view::starts_with(open_str, config.comment_open)) {
2260  if (inja::string_view::starts_with(open_str, config.comment_open_force_lstrip)) {
2261  state = State::CommentStartForceLstrip;
2262  must_lstrip = true;
2263  } else {
2264  state = State::CommentStart;
2265  must_lstrip = config.lstrip_blocks;
2266  }
2267  } else if ((pos == 0 || m_in[pos - 1] == '\n') && inja::string_view::starts_with(open_str, config.line_statement)) {
2268  state = State::LineStart;
2269  } else {
2270  pos += 1; // wasn't actually an opening sequence
2271  goto again;
2272  }
2273 
2274  nonstd::string_view text = string_view::slice(m_in, tok_start, pos);
2275  if (must_lstrip) {
2276  text = clear_final_line_if_whitespace(text);
2277  }
2278 
2279  if (text.empty()) {
2280  goto again; // don't generate empty token
2281  }
2282  return Token(Token::Kind::Text, text);
2283  }
2284  case State::ExpressionStart: {
2285  state = State::ExpressionBody;
2286  pos += config.expression_open.size();
2287  return make_token(Token::Kind::ExpressionOpen);
2288  }
2289  case State::ExpressionStartForceLstrip: {
2290  state = State::ExpressionBody;
2291  pos += config.expression_open_force_lstrip.size();
2292  return make_token(Token::Kind::ExpressionOpen);
2293  }
2294  case State::LineStart: {
2295  state = State::LineBody;
2296  pos += config.line_statement.size();
2297  return make_token(Token::Kind::LineStatementOpen);
2298  }
2299  case State::StatementStart: {
2300  state = State::StatementBody;
2301  pos += config.statement_open.size();
2302  return make_token(Token::Kind::StatementOpen);
2303  }
2304  case State::StatementStartNoLstrip: {
2305  state = State::StatementBody;
2306  pos += config.statement_open_no_lstrip.size();
2307  return make_token(Token::Kind::StatementOpen);
2308  }
2309  case State::StatementStartForceLstrip: {
2310  state = State::StatementBody;
2311  pos += config.statement_open_force_lstrip.size();
2312  return make_token(Token::Kind::StatementOpen);
2313  }
2314  case State::CommentStart: {
2315  state = State::CommentBody;
2316  pos += config.comment_open.size();
2317  return make_token(Token::Kind::CommentOpen);
2318  }
2319  case State::CommentStartForceLstrip: {
2320  state = State::CommentBody;
2321  pos += config.comment_open_force_lstrip.size();
2322  return make_token(Token::Kind::CommentOpen);
2323  }
2324  case State::ExpressionBody:
2325  return scan_body(config.expression_close, Token::Kind::ExpressionClose, config.expression_close_force_rstrip);
2326  case State::LineBody:
2327  return scan_body("\n", Token::Kind::LineStatementClose);
2328  case State::StatementBody:
2329  return scan_body(config.statement_close, Token::Kind::StatementClose, config.statement_close_force_rstrip, config.trim_blocks);
2330  case State::CommentBody: {
2331  // fast-scan to comment close
2332  const size_t end = m_in.substr(pos).find(config.comment_close);
2333  if (end == nonstd::string_view::npos) {
2334  pos = m_in.size();
2335  return make_token(Token::Kind::Eof);
2336  }
2337 
2338  // Check for trim pattern
2339  const bool must_rstrip = inja::string_view::starts_with(m_in.substr(pos + end - 1), config.comment_close_force_rstrip);
2340 
2341  // return the entire comment in the close token
2342  state = State::Text;
2343  pos += end + config.comment_close.size();
2344  Token tok = make_token(Token::Kind::CommentClose);
2345 
2346  if (must_rstrip || config.trim_blocks) {
2347  skip_whitespaces_and_first_newline();
2348  }
2349  return tok;
2350  }
2351  }
2352  }
2353 
2354  const LexerConfig &get_config() const {
2355  return config;
2356  }
2357 };
2358 
2359 } // namespace inja
2360 
2361 #endif // INCLUDE_INJA_LEXER_HPP_
2362 
2363 // #include "node.hpp"
2364 #ifndef INCLUDE_INJA_NODE_HPP_
2365 #define INCLUDE_INJA_NODE_HPP_
2366 
2367 #include <string>
2368 #include <utility>
2369 
2370 #include <nlohmann/json.hpp>
2371 
2372 // #include "function_storage.hpp"
2373 
2374 // #include "string_view.hpp"
2375 
2376 
2377 
2378 namespace inja {
2379 
2380 class NodeVisitor;
2381 class BlockNode;
2382 class TextNode;
2383 class ExpressionNode;
2384 class LiteralNode;
2385 class JsonNode;
2386 class FunctionNode;
2387 class ExpressionListNode;
2388 class StatementNode;
2389 class ForStatementNode;
2390 class ForArrayStatementNode;
2391 class ForObjectStatementNode;
2392 class IfStatementNode;
2393 class IncludeStatementNode;
2394 class ExtendsStatementNode;
2395 class BlockStatementNode;
2396 class SetStatementNode;
2397 
2398 
2400 public:
2401  virtual ~NodeVisitor() = default;
2402 
2403  virtual void visit(const BlockNode& node) = 0;
2404  virtual void visit(const TextNode& node) = 0;
2405  virtual void visit(const ExpressionNode& node) = 0;
2406  virtual void visit(const LiteralNode& node) = 0;
2407  virtual void visit(const JsonNode& node) = 0;
2408  virtual void visit(const FunctionNode& node) = 0;
2409  virtual void visit(const ExpressionListNode& node) = 0;
2410  virtual void visit(const StatementNode& node) = 0;
2411  virtual void visit(const ForStatementNode& node) = 0;
2412  virtual void visit(const ForArrayStatementNode& node) = 0;
2413  virtual void visit(const ForObjectStatementNode& node) = 0;
2414  virtual void visit(const IfStatementNode& node) = 0;
2415  virtual void visit(const IncludeStatementNode& node) = 0;
2416  virtual void visit(const ExtendsStatementNode& node) = 0;
2417  virtual void visit(const BlockStatementNode& node) = 0;
2418  virtual void visit(const SetStatementNode& node) = 0;
2419 };
2420 
2424 class AstNode {
2425 public:
2426  virtual void accept(NodeVisitor& v) const = 0;
2427 
2428  size_t pos;
2429 
2430  AstNode(size_t pos) : pos(pos) { }
2431  virtual ~AstNode() { }
2432 };
2433 
2434 
2435 class BlockNode : public AstNode {
2436 public:
2437  std::vector<std::shared_ptr<AstNode>> nodes;
2438 
2439  explicit BlockNode() : AstNode(0) {}
2440 
2441  void accept(NodeVisitor& v) const {
2442  v.visit(*this);
2443  }
2444 };
2445 
2446 class TextNode : public AstNode {
2447 public:
2448  const size_t length;
2449 
2450  explicit TextNode(size_t pos, size_t length): AstNode(pos), length(length) { }
2451 
2452  void accept(NodeVisitor& v) const {
2453  v.visit(*this);
2454  }
2455 };
2456 
2457 class ExpressionNode : public AstNode {
2458 public:
2459  explicit ExpressionNode(size_t pos) : AstNode(pos) {}
2460 
2461  void accept(NodeVisitor& v) const {
2462  v.visit(*this);
2463  }
2464 };
2465 
2466 class LiteralNode : public ExpressionNode {
2467 public:
2469 
2470  explicit LiteralNode(const nlohmann::json& value, size_t pos) : ExpressionNode(pos), value(value) { }
2471 
2472  void accept(NodeVisitor& v) const {
2473  v.visit(*this);
2474  }
2475 };
2476 
2477 class JsonNode : public ExpressionNode {
2478 public:
2479  const std::string name;
2481 
2482  static std::string convert_dot_to_json_ptr(nonstd::string_view ptr_name) {
2483  std::string result;
2484  do {
2485  nonstd::string_view part;
2486  std::tie(part, ptr_name) = string_view::split(ptr_name, '.');
2487  result.push_back('/');
2488  result.append(part.begin(), part.end());
2489  } while (!ptr_name.empty());
2490  return result;
2491  }
2492 
2493  explicit JsonNode(nonstd::string_view ptr_name, size_t pos) : ExpressionNode(pos), name(ptr_name), ptr(json::json_pointer(convert_dot_to_json_ptr(ptr_name))) { }
2494 
2495  void accept(NodeVisitor& v) const {
2496  v.visit(*this);
2497  }
2498 };
2499 
2502 
2503 public:
2504  enum class Associativity {
2505  Left,
2506  Right,
2507  };
2508 
2509  unsigned int precedence;
2511 
2513 
2514  std::string name;
2515  int number_args; // Should also be negative -> -1 for unknown number
2516  std::vector<std::shared_ptr<ExpressionNode>> arguments;
2518 
2519  explicit FunctionNode(nonstd::string_view name, size_t pos) : ExpressionNode(pos), precedence(8), associativity(Associativity::Left), operation(Op::Callback), name(name), number_args(1) { }
2520  explicit FunctionNode(Op operation, size_t pos) : ExpressionNode(pos), operation(operation), number_args(1) {
2521  switch (operation) {
2522  case Op::Not: {
2523  number_args = 1;
2524  precedence = 4;
2525  associativity = Associativity::Left;
2526  } break;
2527  case Op::And: {
2528  number_args = 2;
2529  precedence = 1;
2530  associativity = Associativity::Left;
2531  } break;
2532  case Op::Or: {
2533  number_args = 2;
2534  precedence = 1;
2535  associativity = Associativity::Left;
2536  } break;
2537  case Op::In: {
2538  number_args = 2;
2539  precedence = 2;
2540  associativity = Associativity::Left;
2541  } break;
2542  case Op::Equal: {
2543  number_args = 2;
2544  precedence = 2;
2545  associativity = Associativity::Left;
2546  } break;
2547  case Op::NotEqual: {
2548  number_args = 2;
2549  precedence = 2;
2550  associativity = Associativity::Left;
2551  } break;
2552  case Op::Greater: {
2553  number_args = 2;
2554  precedence = 2;
2555  associativity = Associativity::Left;
2556  } break;
2557  case Op::GreaterEqual: {
2558  number_args = 2;
2559  precedence = 2;
2560  associativity = Associativity::Left;
2561  } break;
2562  case Op::Less: {
2563  number_args = 2;
2564  precedence = 2;
2565  associativity = Associativity::Left;
2566  } break;
2567  case Op::LessEqual: {
2568  number_args = 2;
2569  precedence = 2;
2570  associativity = Associativity::Left;
2571  } break;
2572  case Op::Add: {
2573  number_args = 2;
2574  precedence = 3;
2575  associativity = Associativity::Left;
2576  } break;
2577  case Op::Subtract: {
2578  number_args = 2;
2579  precedence = 3;
2580  associativity = Associativity::Left;
2581  } break;
2582  case Op::Multiplication: {
2583  number_args = 2;
2584  precedence = 4;
2585  associativity = Associativity::Left;
2586  } break;
2587  case Op::Division: {
2588  number_args = 2;
2589  precedence = 4;
2590  associativity = Associativity::Left;
2591  } break;
2592  case Op::Power: {
2593  number_args = 2;
2594  precedence = 5;
2595  associativity = Associativity::Right;
2596  } break;
2597  case Op::Modulo: {
2598  number_args = 2;
2599  precedence = 4;
2600  associativity = Associativity::Left;
2601  } break;
2602  case Op::AtId: {
2603  number_args = 2;
2604  precedence = 8;
2605  associativity = Associativity::Left;
2606  } break;
2607  default: {
2608  precedence = 1;
2609  associativity = Associativity::Left;
2610  }
2611  }
2612  }
2613 
2614  void accept(NodeVisitor& v) const {
2615  v.visit(*this);
2616  }
2617 };
2618 
2619 class ExpressionListNode : public AstNode {
2620 public:
2621  std::shared_ptr<ExpressionNode> root;
2622 
2623  explicit ExpressionListNode() : AstNode(0) { }
2624  explicit ExpressionListNode(size_t pos) : AstNode(pos) { }
2625 
2626  void accept(NodeVisitor& v) const {
2627  v.visit(*this);
2628  }
2629 };
2630 
2631 class StatementNode : public AstNode {
2632 public:
2633  StatementNode(size_t pos) : AstNode(pos) { }
2634 
2635  virtual void accept(NodeVisitor& v) const = 0;
2636 };
2637 
2639 public:
2643 
2644  ForStatementNode(BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent) { }
2645 
2646  virtual void accept(NodeVisitor& v) const = 0;
2647 };
2648 
2650 public:
2651  const std::string value;
2652 
2653  explicit ForArrayStatementNode(const std::string& value, BlockNode *const parent, size_t pos) : ForStatementNode(parent, pos), value(value) { }
2654 
2655  void accept(NodeVisitor& v) const {
2656  v.visit(*this);
2657  }
2658 };
2659 
2661 public:
2662  const std::string key;
2663  const std::string value;
2664 
2665  explicit ForObjectStatementNode(const std::string& key, const std::string& value, BlockNode *const parent, size_t pos) : ForStatementNode(parent, pos), key(key), value(value) { }
2666 
2667  void accept(NodeVisitor& v) const {
2668  v.visit(*this);
2669  }
2670 };
2671 
2673 public:
2678 
2679  const bool is_nested;
2680  bool has_false_statement {false};
2681 
2682  explicit IfStatementNode(BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent), is_nested(false) { }
2683  explicit IfStatementNode(bool is_nested, BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent), is_nested(is_nested) { }
2684 
2685  void accept(NodeVisitor& v) const {
2686  v.visit(*this);
2687  }
2688 };
2689 
2691 public:
2692  const std::string file;
2693 
2694  explicit IncludeStatementNode(const std::string& file, size_t pos) : StatementNode(pos), file(file) { }
2695 
2696  void accept(NodeVisitor& v) const {
2697  v.visit(*this);
2698  }
2699 };
2700 
2702 public:
2703  const std::string file;
2704 
2705  explicit ExtendsStatementNode(const std::string& file, size_t pos) : StatementNode(pos), file(file) { }
2706 
2707  void accept(NodeVisitor& v) const {
2708  v.visit(*this);
2709  };
2710 };
2711 
2713 public:
2714  const std::string name;
2717 
2718  explicit BlockStatementNode(BlockNode *const parent, const std::string& name, size_t pos) : StatementNode(pos), name(name), parent(parent) { }
2719 
2720  void accept(NodeVisitor& v) const {
2721  v.visit(*this);
2722  };
2723 };
2724 
2726 public:
2727  const std::string key;
2729 
2730  explicit SetStatementNode(const std::string& key, size_t pos) : StatementNode(pos), key(key) { }
2731 
2732  void accept(NodeVisitor& v) const {
2733  v.visit(*this);
2734  }
2735 };
2736 
2737 } // namespace inja
2738 
2739 #endif // INCLUDE_INJA_NODE_HPP_
2740 
2741 // #include "template.hpp"
2742 #ifndef INCLUDE_INJA_TEMPLATE_HPP_
2743 #define INCLUDE_INJA_TEMPLATE_HPP_
2744 
2745 #include <map>
2746 #include <memory>
2747 #include <string>
2748 #include <vector>
2749 
2750 // #include "node.hpp"
2751 
2752 // #include "statistics.hpp"
2753 #ifndef INCLUDE_INJA_STATISTICS_HPP_
2754 #define INCLUDE_INJA_STATISTICS_HPP_
2755 
2756 // #include "node.hpp"
2757 
2758 
2759 
2760 namespace inja {
2761 
2766  void visit(const BlockNode& node) {
2767  for (auto& n : node.nodes) {
2768  n->accept(*this);
2769  }
2770  }
2771 
2772  void visit(const TextNode&) { }
2773  void visit(const ExpressionNode&) { }
2774  void visit(const LiteralNode&) { }
2775 
2776  void visit(const JsonNode&) {
2777  variable_counter += 1;
2778  }
2779 
2780  void visit(const FunctionNode& node) {
2781  for (auto& n : node.arguments) {
2782  n->accept(*this);
2783  }
2784  }
2785 
2786  void visit(const ExpressionListNode& node) {
2787  node.root->accept(*this);
2788  }
2789 
2790  void visit(const StatementNode&) { }
2791  void visit(const ForStatementNode&) { }
2792 
2793  void visit(const ForArrayStatementNode& node) {
2794  node.condition.accept(*this);
2795  node.body.accept(*this);
2796  }
2797 
2798  void visit(const ForObjectStatementNode& node) {
2799  node.condition.accept(*this);
2800  node.body.accept(*this);
2801  }
2802 
2803  void visit(const IfStatementNode& node) {
2804  node.condition.accept(*this);
2805  node.true_statement.accept(*this);
2806  node.false_statement.accept(*this);
2807  }
2808 
2809  void visit(const IncludeStatementNode&) { }
2810 
2811  void visit(const ExtendsStatementNode&) { }
2812 
2813  void visit(const BlockStatementNode& node) {
2814  node.block.accept(*this);
2815  }
2816 
2817  void visit(const SetStatementNode&) { }
2818 
2819 public:
2820  unsigned int variable_counter;
2821 
2822  explicit StatisticsVisitor() : variable_counter(0) { }
2823 };
2824 
2825 } // namespace inja
2826 
2827 #endif // INCLUDE_INJA_STATISTICS_HPP_
2828 
2829 
2830 
2831 namespace inja {
2832 
2836 struct Template {
2838  std::string content;
2839  std::map<std::string, std::shared_ptr<BlockStatementNode>> block_storage;
2840 
2841  explicit Template() { }
2842  explicit Template(const std::string& content): content(content) { }
2843 
2846  auto statistic_visitor = StatisticsVisitor();
2847  root.accept(statistic_visitor);
2848  return statistic_visitor.variable_counter;
2849  }
2850 };
2851 
2852 using TemplateStorage = std::map<std::string, Template>;
2853 
2854 } // namespace inja
2855 
2856 #endif // INCLUDE_INJA_TEMPLATE_HPP_
2857 
2858 // #include "token.hpp"
2859 
2860 // #include "utils.hpp"
2861 
2862 
2863 #include <nlohmann/json.hpp>
2864 
2865 namespace inja {
2866 
2870 class Parser {
2871  const ParserConfig &config;
2872 
2876 
2877  Token tok, peek_tok;
2878  bool have_peek_tok {false};
2879 
2880  size_t current_paren_level {0};
2881  size_t current_bracket_level {0};
2882  size_t current_brace_level {0};
2883 
2884  nonstd::string_view json_literal_start;
2885 
2886  BlockNode *current_block {nullptr};
2887  ExpressionListNode *current_expression_list {nullptr};
2888  std::stack<std::pair<FunctionNode*, size_t>> function_stack;
2889  std::vector<std::shared_ptr<ExpressionNode>> arguments;
2890 
2891  std::stack<std::shared_ptr<FunctionNode>> operator_stack;
2892  std::stack<IfStatementNode*> if_statement_stack;
2893  std::stack<ForStatementNode*> for_statement_stack;
2894  std::stack<BlockStatementNode*> block_statement_stack;
2895 
2896  inline void throw_parser_error(const std::string &message) {
2898  }
2899 
2900  inline void get_next_token() {
2901  if (have_peek_tok) {
2902  tok = peek_tok;
2903  have_peek_tok = false;
2904  } else {
2905  tok = lexer.scan();
2906  }
2907  }
2908 
2909  inline void get_peek_token() {
2910  if (!have_peek_tok) {
2911  peek_tok = lexer.scan();
2912  have_peek_tok = true;
2913  }
2914  }
2915 
2916  inline void add_json_literal(const char* content_ptr) {
2917  nonstd::string_view json_text(json_literal_start.data(), tok.text.data() - json_literal_start.data() + tok.text.size());
2918  arguments.emplace_back(std::make_shared<LiteralNode>(json::parse(json_text), json_text.data() - content_ptr));
2919  }
2920 
2921  inline void add_operator() {
2922  auto function = operator_stack.top();
2923  operator_stack.pop();
2924 
2925  for (int i = 0; i < function->number_args; ++i) {
2926  function->arguments.insert(function->arguments.begin(), arguments.back());
2927  arguments.pop_back();
2928  }
2929  arguments.emplace_back(function);
2930  }
2931 
2932  void add_to_template_storage(nonstd::string_view path, std::string& template_name) {
2933  if (config.search_included_templates_in_files && template_storage.find(template_name) == template_storage.end()) {
2934  // Build the relative path
2935  template_name = static_cast<std::string>(path) + template_name;
2936  if (template_name.compare(0, 2, "./") == 0) {
2937  template_name.erase(0, 2);
2938  }
2939 
2940  if (template_storage.find(template_name) == template_storage.end()) {
2941  auto include_template = Template(load_file(template_name));
2942  template_storage.emplace(template_name, include_template);
2943  parse_into_template(template_storage[template_name], template_name);
2944  }
2945  }
2946  }
2947 
2948  bool parse_expression(Template &tmpl, Token::Kind closing) {
2949  while (tok.kind != closing && tok.kind != Token::Kind::Eof) {
2950  // Literals
2951  switch (tok.kind) {
2952  case Token::Kind::String: {
2953  if (current_brace_level == 0 && current_bracket_level == 0) {
2954  json_literal_start = tok.text;
2955  add_json_literal(tmpl.content.c_str());
2956  }
2957 
2958  } break;
2959  case Token::Kind::Number: {
2960  if (current_brace_level == 0 && current_bracket_level == 0) {
2961  json_literal_start = tok.text;
2962  add_json_literal(tmpl.content.c_str());
2963  }
2964 
2965  } break;
2966  case Token::Kind::LeftBracket: {
2967  if (current_brace_level == 0 && current_bracket_level == 0) {
2968  json_literal_start = tok.text;
2969  }
2970  current_bracket_level += 1;
2971 
2972  } break;
2973  case Token::Kind::LeftBrace: {
2974  if (current_brace_level == 0 && current_bracket_level == 0) {
2975  json_literal_start = tok.text;
2976  }
2977  current_brace_level += 1;
2978 
2979  } break;
2980  case Token::Kind::RightBracket: {
2981  if (current_bracket_level == 0) {
2982  throw_parser_error("unexpected ']'");
2983  }
2984 
2985  current_bracket_level -= 1;
2986  if (current_brace_level == 0 && current_bracket_level == 0) {
2987  add_json_literal(tmpl.content.c_str());
2988  }
2989 
2990  } break;
2991  case Token::Kind::RightBrace: {
2992  if (current_brace_level == 0) {
2993  throw_parser_error("unexpected '}'");
2994  }
2995 
2996  current_brace_level -= 1;
2997  if (current_brace_level == 0 && current_bracket_level == 0) {
2998  add_json_literal(tmpl.content.c_str());
2999  }
3000 
3001  } break;
3002  case Token::Kind::Id: {
3003  get_peek_token();
3004 
3005  // Json Literal
3006  if (tok.text == static_cast<decltype(tok.text)>("true") || tok.text == static_cast<decltype(tok.text)>("false") || tok.text == static_cast<decltype(tok.text)>("null")) {
3007  if (current_brace_level == 0 && current_bracket_level == 0) {
3008  json_literal_start = tok.text;
3009  add_json_literal(tmpl.content.c_str());
3010  }
3011 
3012  // Operator
3013  } else if (tok.text == "and" || tok.text == "or" || tok.text == "in" || tok.text == "not") {
3014  goto parse_operator;
3015 
3016  // Functions
3017  } else if (peek_tok.kind == Token::Kind::LeftParen) {
3018  operator_stack.emplace(std::make_shared<FunctionNode>(static_cast<std::string>(tok.text), tok.text.data() - tmpl.content.c_str()));
3019  function_stack.emplace(operator_stack.top().get(), current_paren_level);
3020 
3021  // Variables
3022  } else {
3023  arguments.emplace_back(std::make_shared<JsonNode>(static_cast<std::string>(tok.text), tok.text.data() - tmpl.content.c_str()));
3024  }
3025 
3026  // Operators
3027  } break;
3028  case Token::Kind::Equal:
3029  case Token::Kind::NotEqual:
3030  case Token::Kind::GreaterThan:
3031  case Token::Kind::GreaterEqual:
3032  case Token::Kind::LessThan:
3033  case Token::Kind::LessEqual:
3034  case Token::Kind::Plus:
3035  case Token::Kind::Minus:
3036  case Token::Kind::Times:
3037  case Token::Kind::Slash:
3038  case Token::Kind::Power:
3039  case Token::Kind::Percent:
3040  case Token::Kind::Dot: {
3041 
3042  parse_operator:
3043  FunctionStorage::Operation operation;
3044  switch (tok.kind) {
3045  case Token::Kind::Id: {
3046  if (tok.text == "and") {
3047  operation = FunctionStorage::Operation::And;
3048  } else if (tok.text == "or") {
3049  operation = FunctionStorage::Operation::Or;
3050  } else if (tok.text == "in") {
3051  operation = FunctionStorage::Operation::In;
3052  } else if (tok.text == "not") {
3053  operation = FunctionStorage::Operation::Not;
3054  } else {
3055  throw_parser_error("unknown operator in parser.");
3056  }
3057  } break;
3058  case Token::Kind::Equal: {
3059  operation = FunctionStorage::Operation::Equal;
3060  } break;
3061  case Token::Kind::NotEqual: {
3062  operation = FunctionStorage::Operation::NotEqual;
3063  } break;
3064  case Token::Kind::GreaterThan: {
3065  operation = FunctionStorage::Operation::Greater;
3066  } break;
3067  case Token::Kind::GreaterEqual: {
3068  operation = FunctionStorage::Operation::GreaterEqual;
3069  } break;
3070  case Token::Kind::LessThan: {
3071  operation = FunctionStorage::Operation::Less;
3072  } break;
3073  case Token::Kind::LessEqual: {
3074  operation = FunctionStorage::Operation::LessEqual;
3075  } break;
3076  case Token::Kind::Plus: {
3077  operation = FunctionStorage::Operation::Add;
3078  } break;
3079  case Token::Kind::Minus: {
3080  operation = FunctionStorage::Operation::Subtract;
3081  } break;
3082  case Token::Kind::Times: {
3083  operation = FunctionStorage::Operation::Multiplication;
3084  } break;
3085  case Token::Kind::Slash: {
3086  operation = FunctionStorage::Operation::Division;
3087  } break;
3088  case Token::Kind::Power: {
3089  operation = FunctionStorage::Operation::Power;
3090  } break;
3091  case Token::Kind::Percent: {
3092  operation = FunctionStorage::Operation::Modulo;
3093  } break;
3094  case Token::Kind::Dot: {
3095  operation = FunctionStorage::Operation::AtId;
3096  } break;
3097  default: {
3098  throw_parser_error("unknown operator in parser.");
3099  }
3100  }
3101  auto function_node = std::make_shared<FunctionNode>(operation, tok.text.data() - tmpl.content.c_str());
3102 
3103  while (!operator_stack.empty() && ((operator_stack.top()->precedence > function_node->precedence) || (operator_stack.top()->precedence == function_node->precedence && function_node->associativity == FunctionNode::Associativity::Left)) && (operator_stack.top()->operation != FunctionStorage::Operation::ParenLeft)) {
3104  add_operator();
3105  }
3106 
3107  operator_stack.emplace(function_node);
3108 
3109  } break;
3110  case Token::Kind::Comma: {
3111  if (current_brace_level == 0 && current_bracket_level == 0) {
3112  if (function_stack.empty()) {
3113  throw_parser_error("unexpected ','");
3114  }
3115 
3116  function_stack.top().first->number_args += 1;
3117  }
3118 
3119  } break;
3120  case Token::Kind::Colon: {
3121  if (current_brace_level == 0 && current_bracket_level == 0) {
3122  throw_parser_error("unexpected ':'");
3123  }
3124 
3125  } break;
3126  case Token::Kind::LeftParen: {
3127  current_paren_level += 1;
3128  operator_stack.emplace(std::make_shared<FunctionNode>(FunctionStorage::Operation::ParenLeft, tok.text.data() - tmpl.content.c_str()));
3129 
3130  get_peek_token();
3131  if (peek_tok.kind == Token::Kind::RightParen) {
3132  if (!function_stack.empty() && function_stack.top().second == current_paren_level - 1) {
3133  function_stack.top().first->number_args = 0;
3134  }
3135  }
3136 
3137  } break;
3138  case Token::Kind::RightParen: {
3139  current_paren_level -= 1;
3140  while (!operator_stack.empty() && operator_stack.top()->operation != FunctionStorage::Operation::ParenLeft) {
3141  add_operator();
3142  }
3143 
3144  if (!operator_stack.empty() && operator_stack.top()->operation == FunctionStorage::Operation::ParenLeft) {
3145  operator_stack.pop();
3146  }
3147 
3148  if (!function_stack.empty() && function_stack.top().second == current_paren_level) {
3149  auto func = function_stack.top().first;
3150  auto function_data = function_storage.find_function(func->name, func->number_args);
3151  if (function_data.operation == FunctionStorage::Operation::None) {
3152  throw_parser_error("unknown function " + func->name);
3153  }
3154  func->operation = function_data.operation;
3155  if (function_data.operation == FunctionStorage::Operation::Callback) {
3156  func->callback = function_data.callback;
3157  }
3158 
3159  if (operator_stack.empty()) {
3160  throw_parser_error("internal error at function " + func->name);
3161  }
3162 
3163  add_operator();
3164  function_stack.pop();
3165  }
3166  }
3167  default:
3168  break;
3169  }
3170 
3171  get_next_token();
3172  }
3173 
3174  while (!operator_stack.empty()) {
3175  add_operator();
3176  }
3177 
3178  if (arguments.size() == 1) {
3179  current_expression_list->root = arguments[0];
3180  arguments = {};
3181 
3182  } else if (arguments.size() > 1) {
3183  throw_parser_error("malformed expression");
3184  }
3185 
3186  return true;
3187  }
3188 
3189  bool parse_statement(Template &tmpl, Token::Kind closing, nonstd::string_view path) {
3190  if (tok.kind != Token::Kind::Id) {
3191  return false;
3192  }
3193 
3194  if (tok.text == static_cast<decltype(tok.text)>("if")) {
3195  get_next_token();
3196 
3197  auto if_statement_node = std::make_shared<IfStatementNode>(current_block, tok.text.data() - tmpl.content.c_str());
3198  current_block->nodes.emplace_back(if_statement_node);
3199  if_statement_stack.emplace(if_statement_node.get());
3200  current_block = &if_statement_node->true_statement;
3201  current_expression_list = &if_statement_node->condition;
3202 
3203  if (!parse_expression(tmpl, closing)) {
3204  return false;
3205  }
3206 
3207  } else if (tok.text == static_cast<decltype(tok.text)>("else")) {
3208  if (if_statement_stack.empty()) {
3209  throw_parser_error("else without matching if");
3210  }
3211  auto &if_statement_data = if_statement_stack.top();
3212  get_next_token();
3213 
3214  if_statement_data->has_false_statement = true;
3215  current_block = &if_statement_data->false_statement;
3216 
3217  // Chained else if
3218  if (tok.kind == Token::Kind::Id && tok.text == static_cast<decltype(tok.text)>("if")) {
3219  get_next_token();
3220 
3221  auto if_statement_node = std::make_shared<IfStatementNode>(true, current_block, tok.text.data() - tmpl.content.c_str());
3222  current_block->nodes.emplace_back(if_statement_node);
3223  if_statement_stack.emplace(if_statement_node.get());
3224  current_block = &if_statement_node->true_statement;
3225  current_expression_list = &if_statement_node->condition;
3226 
3227  if (!parse_expression(tmpl, closing)) {
3228  return false;
3229  }
3230  }
3231 
3232  } else if (tok.text == static_cast<decltype(tok.text)>("endif")) {
3233  if (if_statement_stack.empty()) {
3234  throw_parser_error("endif without matching if");
3235  }
3236 
3237  // Nested if statements
3238  while (if_statement_stack.top()->is_nested) {
3239  if_statement_stack.pop();
3240  }
3241 
3242  auto &if_statement_data = if_statement_stack.top();
3243  get_next_token();
3244 
3245  current_block = if_statement_data->parent;
3246  if_statement_stack.pop();
3247 
3248  } else if (tok.text == static_cast<decltype(tok.text)>("block")) {
3249  get_next_token();
3250 
3251  if (tok.kind != Token::Kind::Id) {
3252  throw_parser_error("expected block name, got '" + tok.describe() + "'");
3253  }
3254 
3255  const std::string block_name = static_cast<std::string>(tok.text);
3256 
3257  auto block_statement_node = std::make_shared<BlockStatementNode>(current_block, block_name, tok.text.data() - tmpl.content.c_str());
3258  current_block->nodes.emplace_back(block_statement_node);
3259  block_statement_stack.emplace(block_statement_node.get());
3260  current_block = &block_statement_node->block;
3261  auto success = tmpl.block_storage.emplace(block_name, block_statement_node);
3262  if (!success.second) {
3263  throw_parser_error("block with the name '" + block_name + "' does already exist");
3264  }
3265 
3266  get_next_token();
3267 
3268  } else if (tok.text == static_cast<decltype(tok.text)>("endblock")) {
3269  if (block_statement_stack.empty()) {
3270  throw_parser_error("endblock without matching block");
3271  }
3272 
3273  auto &block_statement_data = block_statement_stack.top();
3274  get_next_token();
3275 
3276  current_block = block_statement_data->parent;
3277  block_statement_stack.pop();
3278 
3279  } else if (tok.text == static_cast<decltype(tok.text)>("for")) {
3280  get_next_token();
3281 
3282  // options: for a in arr; for a, b in obj
3283  if (tok.kind != Token::Kind::Id) {
3284  throw_parser_error("expected id, got '" + tok.describe() + "'");
3285  }
3286 
3287  Token value_token = tok;
3288  get_next_token();
3289 
3290  // Object type
3291  std::shared_ptr<ForStatementNode> for_statement_node;
3292  if (tok.kind == Token::Kind::Comma) {
3293  get_next_token();
3294  if (tok.kind != Token::Kind::Id) {
3295  throw_parser_error("expected id, got '" + tok.describe() + "'");
3296  }
3297 
3298  Token key_token = std::move(value_token);
3299  value_token = tok;
3300  get_next_token();
3301 
3302  for_statement_node = std::make_shared<ForObjectStatementNode>(static_cast<std::string>(key_token.text), static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
3303 
3304  // Array type
3305  } else {
3306  for_statement_node = std::make_shared<ForArrayStatementNode>(static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
3307  }
3308 
3309  current_block->nodes.emplace_back(for_statement_node);
3310  for_statement_stack.emplace(for_statement_node.get());
3311  current_block = &for_statement_node->body;
3312  current_expression_list = &for_statement_node->condition;
3313 
3314  if (tok.kind != Token::Kind::Id || tok.text != static_cast<decltype(tok.text)>("in")) {
3315  throw_parser_error("expected 'in', got '" + tok.describe() + "'");
3316  }
3317  get_next_token();
3318 
3319  if (!parse_expression(tmpl, closing)) {
3320  return false;
3321  }
3322 
3323  } else if (tok.text == static_cast<decltype(tok.text)>("endfor")) {
3324  if (for_statement_stack.empty()) {
3325  throw_parser_error("endfor without matching for");
3326  }
3327 
3328  auto &for_statement_data = for_statement_stack.top();
3329  get_next_token();
3330 
3331  current_block = for_statement_data->parent;
3332  for_statement_stack.pop();
3333 
3334  } else if (tok.text == static_cast<decltype(tok.text)>("include")) {
3335  get_next_token();
3336 
3337  if (tok.kind != Token::Kind::String) {
3338  throw_parser_error("expected string, got '" + tok.describe() + "'");
3339  }
3340 
3341  std::string template_name = json::parse(tok.text).get_ref<const std::string &>();
3342  add_to_template_storage(path, template_name);
3343 
3344  current_block->nodes.emplace_back(std::make_shared<IncludeStatementNode>(template_name, tok.text.data() - tmpl.content.c_str()));
3345 
3346  get_next_token();
3347 
3348  } else if (tok.text == static_cast<decltype(tok.text)>("extends")) {
3349  get_next_token();
3350 
3351  if (tok.kind != Token::Kind::String) {
3352  throw_parser_error("expected string, got '" + tok.describe() + "'");
3353  }
3354 
3355  std::string template_name = json::parse(tok.text).get_ref<const std::string &>();
3356  add_to_template_storage(path, template_name);
3357 
3358  current_block->nodes.emplace_back(std::make_shared<ExtendsStatementNode>(template_name, tok.text.data() - tmpl.content.c_str()));
3359 
3360  get_next_token();
3361 
3362  } else if (tok.text == static_cast<decltype(tok.text)>("set")) {
3363  get_next_token();
3364 
3365  if (tok.kind != Token::Kind::Id) {
3366  throw_parser_error("expected variable name, got '" + tok.describe() + "'");
3367  }
3368 
3369  std::string key = static_cast<std::string>(tok.text);
3370  get_next_token();
3371 
3372  auto set_statement_node = std::make_shared<SetStatementNode>(key, tok.text.data() - tmpl.content.c_str());
3373  current_block->nodes.emplace_back(set_statement_node);
3374  current_expression_list = &set_statement_node->expression;
3375 
3376  if (tok.text != static_cast<decltype(tok.text)>("=")) {
3377  throw_parser_error("expected '=', got '" + tok.describe() + "'");
3378  }
3379  get_next_token();
3380 
3381  if (!parse_expression(tmpl, closing)) {
3382  return false;
3383  }
3384 
3385  } else {
3386  return false;
3387  }
3388  return true;
3389  }
3390 
3391  void parse_into(Template &tmpl, nonstd::string_view path) {
3392  lexer.start(tmpl.content);
3393  current_block = &tmpl.root;
3394 
3395  for (;;) {
3396  get_next_token();
3397  switch (tok.kind) {
3398  case Token::Kind::Eof: {
3399  if (!if_statement_stack.empty()) {
3400  throw_parser_error("unmatched if");
3401  }
3402  if (!for_statement_stack.empty()) {
3403  throw_parser_error("unmatched for");
3404  }
3405  } return;
3406  case Token::Kind::Text: {
3407  current_block->nodes.emplace_back(std::make_shared<TextNode>(tok.text.data() - tmpl.content.c_str(), tok.text.size()));
3408  } break;
3409  case Token::Kind::StatementOpen: {
3410  get_next_token();
3411  if (!parse_statement(tmpl, Token::Kind::StatementClose, path)) {
3412  throw_parser_error("expected statement, got '" + tok.describe() + "'");
3413  }
3414  if (tok.kind != Token::Kind::StatementClose) {
3415  throw_parser_error("expected statement close, got '" + tok.describe() + "'");
3416  }
3417  } break;
3418  case Token::Kind::LineStatementOpen: {
3419  get_next_token();
3420  if (!parse_statement(tmpl, Token::Kind::LineStatementClose, path)) {
3421  throw_parser_error("expected statement, got '" + tok.describe() + "'");
3422  }
3423  if (tok.kind != Token::Kind::LineStatementClose && tok.kind != Token::Kind::Eof) {
3424  throw_parser_error("expected line statement close, got '" + tok.describe() + "'");
3425  }
3426  } break;
3427  case Token::Kind::ExpressionOpen: {
3428  get_next_token();
3429 
3430  auto expression_list_node = std::make_shared<ExpressionListNode>(tok.text.data() - tmpl.content.c_str());
3431  current_block->nodes.emplace_back(expression_list_node);
3432  current_expression_list = expression_list_node.get();
3433 
3434  if (!parse_expression(tmpl, Token::Kind::ExpressionClose)) {
3435  throw_parser_error("expected expression, got '" + tok.describe() + "'");
3436  }
3437 
3438  if (tok.kind != Token::Kind::ExpressionClose) {
3439  throw_parser_error("expected expression close, got '" + tok.describe() + "'");
3440  }
3441  } break;
3442  case Token::Kind::CommentOpen: {
3443  get_next_token();
3444  if (tok.kind != Token::Kind::CommentClose) {
3445  throw_parser_error("expected comment close, got '" + tok.describe() + "'");
3446  }
3447  } break;
3448  default: {
3449  throw_parser_error("unexpected token '" + tok.describe() + "'");
3450  } break;
3451  }
3452  }
3453  }
3454 
3455 
3456 public:
3457  explicit Parser(const ParserConfig &parser_config, const LexerConfig &lexer_config,
3458  TemplateStorage &template_storage, const FunctionStorage &function_storage)
3459  : config(parser_config), lexer(lexer_config), template_storage(template_storage), function_storage(function_storage) { }
3460 
3461  Template parse(nonstd::string_view input, nonstd::string_view path) {
3462  auto result = Template(static_cast<std::string>(input));
3463  parse_into(result, path);
3464  return result;
3465  }
3466 
3467  Template parse(nonstd::string_view input) {
3468  return parse(input, "./");
3469  }
3470 
3471  void parse_into_template(Template& tmpl, nonstd::string_view filename) {
3472  nonstd::string_view path = filename.substr(0, filename.find_last_of("/\\") + 1);
3473 
3474  // StringRef path = sys::path::parent_path(filename);
3475  auto sub_parser = Parser(config, lexer.get_config(), template_storage, function_storage);
3476  sub_parser.parse_into(tmpl, path);
3477  }
3478 
3479  std::string load_file(nonstd::string_view filename) {
3480  std::ifstream file;
3481  open_file_or_throw(static_cast<std::string>(filename), file);
3482  std::string text((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
3483  return text;
3484  }
3485 };
3486 
3487 } // namespace inja
3488 
3489 #endif // INCLUDE_INJA_PARSER_HPP_
3490 
3491 // #include "renderer.hpp"
3492 #ifndef INCLUDE_INJA_RENDERER_HPP_
3493 #define INCLUDE_INJA_RENDERER_HPP_
3494 
3495 #include <algorithm>
3496 #include <numeric>
3497 #include <string>
3498 #include <utility>
3499 #include <vector>
3500 
3501 #include <nlohmann/json.hpp>
3502 
3503 // #include "config.hpp"
3504 
3505 // #include "exceptions.hpp"
3506 
3507 // #include "node.hpp"
3508 
3509 // #include "template.hpp"
3510 
3511 // #include "utils.hpp"
3512 
3513 
3514 namespace inja {
3515 
3519 class Renderer : public NodeVisitor {
3521 
3522  const RenderConfig config;
3525 
3527  size_t current_level {0};
3528  std::vector<const Template*> template_stack;
3529  std::vector<const BlockStatementNode*> block_statement_stack;
3530 
3532  std::ostream *output_stream;
3533 
3535  json* current_loop_data = &json_additional_data["loop"];
3536 
3537  std::vector<std::shared_ptr<json>> json_tmp_stack;
3538  std::stack<const json*> json_eval_stack;
3539  std::stack<const JsonNode*> not_found_stack;
3540 
3541  bool break_rendering {false};
3542 
3543  bool truthy(const json* data) const {
3544  if (data->is_boolean()) {
3545  return data->get<bool>();
3546  } else if (data->is_number()) {
3547  return (*data != 0);
3548  } else if (data->is_null()) {
3549  return false;
3550  }
3551  return !data->empty();
3552  }
3553 
3554  void print_json(const std::shared_ptr<json> value) {
3555  if (value->is_string()) {
3556  *output_stream << value->get_ref<const json::string_t&>();
3557  } else if (value->is_number_integer()) {
3558  *output_stream << value->get<const json::number_integer_t>();
3559  } else if (value->is_null()) {
3560  } else {
3561  *output_stream << value->dump();
3562  }
3563  }
3564 
3565  const std::shared_ptr<json> eval_expression_list(const ExpressionListNode& expression_list) {
3566  if (!expression_list.root) {
3567  throw_renderer_error("empty expression", expression_list);
3568  }
3569 
3570  expression_list.root->accept(*this);
3571 
3572  if (json_eval_stack.empty()) {
3573  throw_renderer_error("empty expression", expression_list);
3574  } else if (json_eval_stack.size() != 1) {
3575  throw_renderer_error("malformed expression", expression_list);
3576  }
3577 
3578  const auto result = json_eval_stack.top();
3579  json_eval_stack.pop();
3580 
3581  if (!result) {
3582  if (not_found_stack.empty()) {
3583  throw_renderer_error("expression could not be evaluated", expression_list);
3584  }
3585 
3586  auto node = not_found_stack.top();
3587  not_found_stack.pop();
3588 
3589  throw_renderer_error("variable '" + static_cast<std::string>(node->name) + "' not found", *node);
3590  }
3591  return std::make_shared<json>(*result);
3592  }
3593 
3594  void throw_renderer_error(const std::string &message, const AstNode& node) {
3595  SourceLocation loc = get_source_location(current_template->content, node.pos);
3597  }
3598 
3599  template<size_t N, size_t N_start = 0, bool throw_not_found=true>
3600  std::array<const json*, N> get_arguments(const FunctionNode& node) {
3601  if (node.arguments.size() < N_start + N) {
3602  throw_renderer_error("function needs " + std::to_string(N_start + N) + " variables, but has only found " + std::to_string(node.arguments.size()), node);
3603  }
3604 
3605  for (size_t i = N_start; i < N_start + N; i += 1) {
3606  node.arguments[i]->accept(*this);
3607  }
3608 
3609  if (json_eval_stack.size() < N) {
3610  throw_renderer_error("function needs " + std::to_string(N) + " variables, but has only found " + std::to_string(json_eval_stack.size()), node);
3611  }
3612 
3613  std::array<const json*, N> result;
3614  for (size_t i = 0; i < N; i += 1) {
3615  result[N - i - 1] = json_eval_stack.top();
3616  json_eval_stack.pop();
3617 
3618  if (!result[N - i - 1]) {
3619  const auto json_node = not_found_stack.top();
3620  not_found_stack.pop();
3621 
3622  if (throw_not_found) {
3623  throw_renderer_error("variable '" + static_cast<std::string>(json_node->name) + "' not found", *json_node);
3624  }
3625  }
3626  }
3627  return result;
3628  }
3629 
3630  template<bool throw_not_found=true>
3632  const size_t N = node.arguments.size();
3633  for (auto a: node.arguments) {
3634  a->accept(*this);
3635  }
3636 
3637  if (json_eval_stack.size() < N) {
3638  throw_renderer_error("function needs " + std::to_string(N) + " variables, but has only found " + std::to_string(json_eval_stack.size()), node);
3639  }
3640 
3641  Arguments result {N};
3642  for (size_t i = 0; i < N; i += 1) {
3643  result[N - i - 1] = json_eval_stack.top();
3644  json_eval_stack.pop();
3645 
3646  if (!result[N - i - 1]) {
3647  const auto json_node = not_found_stack.top();
3648  not_found_stack.pop();
3649 
3650  if (throw_not_found) {
3651  throw_renderer_error("variable '" + static_cast<std::string>(json_node->name) + "' not found", *json_node);
3652  }
3653  }
3654  }
3655  return result;
3656  }
3657 
3658  void visit(const BlockNode& node) {
3659  for (auto& n : node.nodes) {
3660  n->accept(*this);
3661 
3662  if (break_rendering) {
3663  break;
3664  }
3665  }
3666  }
3667 
3668  void visit(const TextNode& node) {
3669  output_stream->write(current_template->content.c_str() + node.pos, node.length);
3670  }
3671 
3672  void visit(const ExpressionNode&) { }
3673 
3674  void visit(const LiteralNode& node) {
3675  json_eval_stack.push(&node.value);
3676  }
3677 
3678  void visit(const JsonNode& node) {
3679  if (json_additional_data.contains(node.ptr)) {
3680  json_eval_stack.push(&(json_additional_data[node.ptr]));
3681 
3682  } else if (json_input->contains(node.ptr)) {
3683  json_eval_stack.push(&(*json_input)[node.ptr]);
3684 
3685  } else {
3686  // Try to evaluate as a no-argument callback
3687  const auto function_data = function_storage.find_function(node.name, 0);
3688  if (function_data.operation == FunctionStorage::Operation::Callback) {
3689  Arguments empty_args {};
3690  const auto value = std::make_shared<json>(function_data.callback(empty_args));
3691  json_tmp_stack.push_back(value);
3692  json_eval_stack.push(value.get());
3693 
3694  } else {
3695  json_eval_stack.push(nullptr);
3696  not_found_stack.emplace(&node);
3697  }
3698  }
3699  }
3700 
3701  void visit(const FunctionNode& node) {
3702  std::shared_ptr<json> result_ptr;
3703 
3704  switch (node.operation) {
3705  case Op::Not: {
3706  const auto args = get_arguments<1>(node);
3707  result_ptr = std::make_shared<json>(!truthy(args[0]));
3708  json_tmp_stack.push_back(result_ptr);
3709  json_eval_stack.push(result_ptr.get());
3710  } break;
3711  case Op::And: {
3712  result_ptr = std::make_shared<json>(truthy(get_arguments<1, 0>(node)[0]) && truthy(get_arguments<1, 1>(node)[0]));
3713  json_tmp_stack.push_back(result_ptr);
3714  json_eval_stack.push(result_ptr.get());
3715  } break;
3716  case Op::Or: {
3717  result_ptr = std::make_shared<json>(truthy(get_arguments<1, 0>(node)[0]) || truthy(get_arguments<1, 1>(node)[0]));
3718  json_tmp_stack.push_back(result_ptr);
3719  json_eval_stack.push(result_ptr.get());
3720  } break;
3721  case Op::In: {
3722  const auto args = get_arguments<2>(node);
3723  result_ptr = std::make_shared<json>(std::find(args[1]->begin(), args[1]->end(), *args[0]) != args[1]->end());
3724  json_tmp_stack.push_back(result_ptr);
3725  json_eval_stack.push(result_ptr.get());
3726  } break;
3727  case Op::Equal: {
3728  const auto args = get_arguments<2>(node);
3729  result_ptr = std::make_shared<json>(*args[0] == *args[1]);
3730  json_tmp_stack.push_back(result_ptr);
3731  json_eval_stack.push(result_ptr.get());
3732  } break;
3733  case Op::NotEqual: {
3734  const auto args = get_arguments<2>(node);
3735  result_ptr = std::make_shared<json>(*args[0] != *args[1]);
3736  json_tmp_stack.push_back(result_ptr);
3737  json_eval_stack.push(result_ptr.get());
3738  } break;
3739  case Op::Greater: {
3740  const auto args = get_arguments<2>(node);
3741  result_ptr = std::make_shared<json>(*args[0] > *args[1]);
3742  json_tmp_stack.push_back(result_ptr);
3743  json_eval_stack.push(result_ptr.get());
3744  } break;
3745  case Op::GreaterEqual: {
3746  const auto args = get_arguments<2>(node);
3747  result_ptr = std::make_shared<json>(*args[0] >= *args[1]);
3748  json_tmp_stack.push_back(result_ptr);
3749  json_eval_stack.push(result_ptr.get());
3750  } break;
3751  case Op::Less: {
3752  const auto args = get_arguments<2>(node);
3753  result_ptr = std::make_shared<json>(*args[0] < *args[1]);
3754  json_tmp_stack.push_back(result_ptr);
3755  json_eval_stack.push(result_ptr.get());
3756  } break;
3757  case Op::LessEqual: {
3758  const auto args = get_arguments<2>(node);
3759  result_ptr = std::make_shared<json>(*args[0] <= *args[1]);
3760  json_tmp_stack.push_back(result_ptr);
3761  json_eval_stack.push(result_ptr.get());
3762  } break;
3763  case Op::Add: {
3764  const auto args = get_arguments<2>(node);
3765  if (args[0]->is_string() && args[1]->is_string()) {
3766  result_ptr = std::make_shared<json>(args[0]->get_ref<const std::string&>() + args[1]->get_ref<const std::string&>());
3767  json_tmp_stack.push_back(result_ptr);
3768  } else if (args[0]->is_number_integer() && args[1]->is_number_integer()) {
3769  result_ptr = std::make_shared<json>(args[0]->get<int>() + args[1]->get<int>());
3770  json_tmp_stack.push_back(result_ptr);
3771  } else {
3772  result_ptr = std::make_shared<json>(args[0]->get<double>() + args[1]->get<double>());
3773  json_tmp_stack.push_back(result_ptr);
3774  }
3775  json_eval_stack.push(result_ptr.get());
3776  } break;
3777  case Op::Subtract: {
3778  const auto args = get_arguments<2>(node);
3779  if (args[0]->is_number_integer() && args[1]->is_number_integer()) {
3780  result_ptr = std::make_shared<json>(args[0]->get<int>() - args[1]->get<int>());
3781  json_tmp_stack.push_back(result_ptr);
3782  } else {
3783  result_ptr = std::make_shared<json>(args[0]->get<double>() - args[1]->get<double>());
3784  json_tmp_stack.push_back(result_ptr);
3785  }
3786  json_eval_stack.push(result_ptr.get());
3787  } break;
3788  case Op::Multiplication: {
3789  const auto args = get_arguments<2>(node);
3790  if (args[0]->is_number_integer() && args[1]->is_number_integer()) {
3791  result_ptr = std::make_shared<json>(args[0]->get<int>() * args[1]->get<int>());
3792  json_tmp_stack.push_back(result_ptr);
3793  } else {
3794  result_ptr = std::make_shared<json>(args[0]->get<double>() * args[1]->get<double>());
3795  json_tmp_stack.push_back(result_ptr);
3796  }
3797  json_eval_stack.push(result_ptr.get());
3798  } break;
3799  case Op::Division: {
3800  const auto args = get_arguments<2>(node);
3801  if (args[1]->get<double>() == 0) {
3802  throw_renderer_error("division by zero", node);
3803  }
3804  result_ptr = std::make_shared<json>(args[0]->get<double>() / args[1]->get<double>());
3805  json_tmp_stack.push_back(result_ptr);
3806  json_eval_stack.push(result_ptr.get());
3807  } break;
3808  case Op::Power: {
3809  const auto args = get_arguments<2>(node);
3810  if (args[0]->is_number_integer() && args[1]->get<int>() >= 0) {
3811  int result = static_cast<int>(std::pow(args[0]->get<int>(), args[1]->get<int>()));
3812  result_ptr = std::make_shared<json>(std::move(result));
3813  json_tmp_stack.push_back(result_ptr);
3814  } else {
3815  double result = std::pow(args[0]->get<double>(), args[1]->get<int>());
3816  result_ptr = std::make_shared<json>(std::move(result));
3817  json_tmp_stack.push_back(result_ptr);
3818  }
3819  json_eval_stack.push(result_ptr.get());
3820  } break;
3821  case Op::Modulo: {
3822  const auto args = get_arguments<2>(node);
3823  result_ptr = std::make_shared<json>(args[0]->get<int>() % args[1]->get<int>());
3824  json_tmp_stack.push_back(result_ptr);
3825  json_eval_stack.push(result_ptr.get());
3826  } break;
3827  case Op::AtId: {
3828  const auto container = get_arguments<1, 0, false>(node)[0];
3829  node.arguments[1]->accept(*this);
3830  if (not_found_stack.empty()) {
3831  throw_renderer_error("could not find element with given name", node);
3832  }
3833  const auto id_node = not_found_stack.top();
3834  not_found_stack.pop();
3835  json_eval_stack.pop();
3836  json_eval_stack.push(&container->at(id_node->name));
3837  } break;
3838  case Op::At: {
3839  const auto args = get_arguments<2>(node);
3840  if (args[0]->is_object()) {
3841  json_eval_stack.push(&args[0]->at(args[1]->get<std::string>()));
3842  } else {
3843  json_eval_stack.push(&args[0]->at(args[1]->get<int>()));
3844  }
3845  } break;
3846  case Op::Default: {
3847  const auto test_arg = get_arguments<1, 0, false>(node)[0];
3848  json_eval_stack.push(test_arg ? test_arg : get_arguments<1, 1>(node)[0]);
3849  } break;
3850  case Op::DivisibleBy: {
3851  const auto args = get_arguments<2>(node);
3852  const int divisor = args[1]->get<int>();
3853  result_ptr = std::make_shared<json>((divisor != 0) && (args[0]->get<int>() % divisor == 0));
3854  json_tmp_stack.push_back(result_ptr);
3855  json_eval_stack.push(result_ptr.get());
3856  } break;
3857  case Op::Even: {
3858  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->get<int>() % 2 == 0);
3859  json_tmp_stack.push_back(result_ptr);
3860  json_eval_stack.push(result_ptr.get());
3861  } break;
3862  case Op::Exists: {
3863  auto &&name = get_arguments<1>(node)[0]->get_ref<const std::string &>();
3864  result_ptr = std::make_shared<json>(json_input->contains(json::json_pointer(JsonNode::convert_dot_to_json_ptr(name))));
3865  json_tmp_stack.push_back(result_ptr);
3866  json_eval_stack.push(result_ptr.get());
3867  } break;
3868  case Op::ExistsInObject: {
3869  const auto args = get_arguments<2>(node);
3870  auto &&name = args[1]->get_ref<const std::string &>();
3871  result_ptr = std::make_shared<json>(args[0]->find(name) != args[0]->end());
3872  json_tmp_stack.push_back(result_ptr);
3873  json_eval_stack.push(result_ptr.get());
3874  } break;
3875  case Op::First: {
3876  const auto result = &get_arguments<1>(node)[0]->front();
3877  json_eval_stack.push(result);
3878  } break;
3879  case Op::Float: {
3880  result_ptr = std::make_shared<json>(std::stod(get_arguments<1>(node)[0]->get_ref<const std::string &>()));
3881  json_tmp_stack.push_back(result_ptr);
3882  json_eval_stack.push(result_ptr.get());
3883  } break;
3884  case Op::Int: {
3885  result_ptr = std::make_shared<json>(std::stoi(get_arguments<1>(node)[0]->get_ref<const std::string &>()));
3886  json_tmp_stack.push_back(result_ptr);
3887  json_eval_stack.push(result_ptr.get());
3888  } break;
3889  case Op::Last: {
3890  const auto result = &get_arguments<1>(node)[0]->back();
3891  json_eval_stack.push(result);
3892  } break;
3893  case Op::Length: {
3894  const auto val = get_arguments<1>(node)[0];
3895  if (val->is_string()) {
3896  result_ptr = std::make_shared<json>(val->get_ref<const std::string &>().length());
3897  } else {
3898  result_ptr = std::make_shared<json>(val->size());
3899  }
3900  json_tmp_stack.push_back(result_ptr);
3901  json_eval_stack.push(result_ptr.get());
3902  } break;
3903  case Op::Lower: {
3904  std::string result = get_arguments<1>(node)[0]->get<std::string>();
3905  std::transform(result.begin(), result.end(), result.begin(), ::tolower);
3906  result_ptr = std::make_shared<json>(std::move(result));
3907  json_tmp_stack.push_back(result_ptr);
3908  json_eval_stack.push(result_ptr.get());
3909  } break;
3910  case Op::Max: {
3911  const auto args = get_arguments<1>(node);
3912  const auto result = std::max_element(args[0]->begin(), args[0]->end());
3913  json_eval_stack.push(&(*result));
3914  } break;
3915  case Op::Min: {
3916  const auto args = get_arguments<1>(node);
3917  const auto result = std::min_element(args[0]->begin(), args[0]->end());
3918  json_eval_stack.push(&(*result));
3919  } break;
3920  case Op::Odd: {
3921  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->get<int>() % 2 != 0);
3922  json_tmp_stack.push_back(result_ptr);
3923  json_eval_stack.push(result_ptr.get());
3924  } break;
3925  case Op::Range: {
3926  std::vector<int> result(get_arguments<1>(node)[0]->get<int>());
3927  std::iota(result.begin(), result.end(), 0);
3928  result_ptr = std::make_shared<json>(std::move(result));
3929  json_tmp_stack.push_back(result_ptr);
3930  json_eval_stack.push(result_ptr.get());
3931  } break;
3932  case Op::Round: {
3933  const auto args = get_arguments<2>(node);
3934  const int precision = args[1]->get<int>();
3935  const double result = std::round(args[0]->get<double>() * std::pow(10.0, precision)) / std::pow(10.0, precision);
3936  if(0==precision){
3937  result_ptr = std::make_shared<json>(int(result));
3938  }else{
3939  result_ptr = std::make_shared<json>(std::move(result));
3940  }
3941  json_tmp_stack.push_back(result_ptr);
3942  json_eval_stack.push(result_ptr.get());
3943  } break;
3944  case Op::Sort: {
3945  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->get<std::vector<json>>());
3946  std::sort(result_ptr->begin(), result_ptr->end());
3947  json_tmp_stack.push_back(result_ptr);
3948  json_eval_stack.push(result_ptr.get());
3949  } break;
3950  case Op::Upper: {
3951  std::string result = get_arguments<1>(node)[0]->get<std::string>();
3952  std::transform(result.begin(), result.end(), result.begin(), ::toupper);
3953  result_ptr = std::make_shared<json>(std::move(result));
3954  json_tmp_stack.push_back(result_ptr);
3955  json_eval_stack.push(result_ptr.get());
3956  } break;
3957  case Op::IsBoolean: {
3958  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->is_boolean());
3959  json_tmp_stack.push_back(result_ptr);
3960  json_eval_stack.push(result_ptr.get());
3961  } break;
3962  case Op::IsNumber: {
3963  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->is_number());
3964  json_tmp_stack.push_back(result_ptr);
3965  json_eval_stack.push(result_ptr.get());
3966  } break;
3967  case Op::IsInteger: {
3968  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->is_number_integer());
3969  json_tmp_stack.push_back(result_ptr);
3970  json_eval_stack.push(result_ptr.get());
3971  } break;
3972  case Op::IsFloat: {
3973  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->is_number_float());
3974  json_tmp_stack.push_back(result_ptr);
3975  json_eval_stack.push(result_ptr.get());
3976  } break;
3977  case Op::IsObject: {
3978  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->is_object());
3979  json_tmp_stack.push_back(result_ptr);
3980  json_eval_stack.push(result_ptr.get());
3981  } break;
3982  case Op::IsArray: {
3983  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->is_array());
3984  json_tmp_stack.push_back(result_ptr);
3985  json_eval_stack.push(result_ptr.get());
3986  } break;
3987  case Op::IsString: {
3988  result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->is_string());
3989  json_tmp_stack.push_back(result_ptr);
3990  json_eval_stack.push(result_ptr.get());
3991  } break;
3992  case Op::Callback: {
3993  auto args = get_argument_vector(node);
3994  result_ptr = std::make_shared<json>(node.callback(args));
3995  json_tmp_stack.push_back(result_ptr);
3996  json_eval_stack.push(result_ptr.get());
3997  } break;
3998  case Op::Super: {
3999  const auto args = get_argument_vector(node);
4000  const size_t old_level = current_level;
4001  const size_t level_diff = (args.size() == 1) ? args[0]->get<int>() : 1;
4002  const size_t level = current_level + level_diff;
4003 
4004  if (block_statement_stack.empty()) {
4005  throw_renderer_error("super() call is not within a block", node);
4006  }
4007 
4008  if (level < 1 || level > template_stack.size() - 1) {
4009  throw_renderer_error("level of super() call does not match parent templates (between 1 and " + std::to_string(template_stack.size() - 1) + ")", node);
4010  }
4011 
4012  const auto current_block_statement = block_statement_stack.back();
4013  const Template *new_template = template_stack.at(level);
4014  const Template *old_template = current_template;
4015  const auto block_it = new_template->block_storage.find(current_block_statement->name);
4016  if (block_it != new_template->block_storage.end()) {
4017  current_template = new_template;
4018  current_level = level;
4019  block_it->second->block.accept(*this);
4020  current_level = old_level;
4021  current_template = old_template;
4022  } else {
4023  throw_renderer_error("could not find block with name '" + current_block_statement->name + "'", node);
4024  }
4025  result_ptr = std::make_shared<json>(nullptr);
4026  json_tmp_stack.push_back(result_ptr);
4027  json_eval_stack.push(result_ptr.get());
4028  } break;
4029  case Op::Join: {
4030  const auto args = get_arguments<2>(node);
4031  const auto separator = args[1]->get<std::string>();
4032  std::ostringstream os;
4033  std::string sep;
4034  for (const auto& value : *args[0]) {
4035  os << sep;
4036  if (value.is_string()) {
4037  os << value.get<std::string>(); // otherwise the value is surrounded with ""
4038  } else {
4039  os << value;
4040  }
4041  sep = separator;
4042  }
4043  result_ptr = std::make_shared<json>(os.str());
4044  json_tmp_stack.push_back(result_ptr);
4045  json_eval_stack.push(result_ptr.get());
4046  } break;
4047  case Op::ParenLeft:
4048  case Op::ParenRight:
4049  case Op::None:
4050  break;
4051  }
4052  }
4053 
4054  void visit(const ExpressionListNode& node) {
4055  print_json(eval_expression_list(node));
4056  }
4057 
4058  void visit(const StatementNode&) { }
4059 
4060  void visit(const ForStatementNode&) { }
4061 
4062  void visit(const ForArrayStatementNode& node) {
4063  const auto result = eval_expression_list(node.condition);
4064  if (!result->is_array()) {
4065  throw_renderer_error("object must be an array", node);
4066  }
4067 
4068  if (!current_loop_data->empty()) {
4069  auto tmp = *current_loop_data; // Because of clang-3
4070  (*current_loop_data)["parent"] = std::move(tmp);
4071  }
4072 
4073  size_t index = 0;
4074  (*current_loop_data)["is_first"] = true;
4075  (*current_loop_data)["is_last"] = (result->size() <= 1);
4076  for (auto it = result->begin(); it != result->end(); ++it) {
4077  json_additional_data[static_cast<std::string>(node.value)] = *it;
4078 
4079  (*current_loop_data)["index"] = index;
4080  (*current_loop_data)["index1"] = index + 1;
4081  if (index == 1) {
4082  (*current_loop_data)["is_first"] = false;
4083  }
4084  if (index == result->size() - 1) {
4085  (*current_loop_data)["is_last"] = true;
4086  }
4087 
4088  node.body.accept(*this);
4089  ++index;
4090  }
4091 
4092  json_additional_data[static_cast<std::string>(node.value)].clear();
4093  if (!(*current_loop_data)["parent"].empty()) {
4094  const auto tmp = (*current_loop_data)["parent"];
4095  *current_loop_data = std::move(tmp);
4096  } else {
4097  current_loop_data = &json_additional_data["loop"];
4098  }
4099  }
4100 
4101  void visit(const ForObjectStatementNode& node) {
4102  const auto result = eval_expression_list(node.condition);
4103  if (!result->is_object()) {
4104  throw_renderer_error("object must be an object", node);
4105  }
4106 
4107  if (!current_loop_data->empty()) {
4108  (*current_loop_data)["parent"] = std::move(*current_loop_data);
4109  }
4110 
4111  size_t index = 0;
4112  (*current_loop_data)["is_first"] = true;
4113  (*current_loop_data)["is_last"] = (result->size() <= 1);
4114  for (auto it = result->begin(); it != result->end(); ++it) {
4115  json_additional_data[static_cast<std::string>(node.key)] = it.key();
4116  json_additional_data[static_cast<std::string>(node.value)] = it.value();
4117 
4118  (*current_loop_data)["index"] = index;
4119  (*current_loop_data)["index1"] = index + 1;
4120  if (index == 1) {
4121  (*current_loop_data)["is_first"] = false;
4122  }
4123  if (index == result->size() - 1) {
4124  (*current_loop_data)["is_last"] = true;
4125  }
4126 
4127  node.body.accept(*this);
4128  ++index;
4129  }
4130 
4131  json_additional_data[static_cast<std::string>(node.key)].clear();
4132  json_additional_data[static_cast<std::string>(node.value)].clear();
4133  if (!(*current_loop_data)["parent"].empty()) {
4134  *current_loop_data = std::move((*current_loop_data)["parent"]);
4135  } else {
4136  current_loop_data = &json_additional_data["loop"];
4137  }
4138  }
4139 
4140  void visit(const IfStatementNode& node) {
4141  const auto result = eval_expression_list(node.condition);
4142  if (truthy(result.get())) {
4143  node.true_statement.accept(*this);
4144  } else if (node.has_false_statement) {
4145  node.false_statement.accept(*this);
4146  }
4147  }
4148 
4149  void visit(const IncludeStatementNode& node) {
4150  auto sub_renderer = Renderer(config, template_storage, function_storage);
4151  const auto included_template_it = template_storage.find(node.file);
4152  if (included_template_it != template_storage.end()) {
4153  sub_renderer.render_to(*output_stream, included_template_it->second, *json_input, &json_additional_data);
4154  } else if (config.throw_at_missing_includes) {
4155  throw_renderer_error("include '" + node.file + "' not found", node);
4156  }
4157  }
4158 
4159  void visit(const ExtendsStatementNode& node) {
4160  const auto included_template_it = template_storage.find(node.file);
4161  if (included_template_it != template_storage.end()) {
4162  const Template *parent_template = &included_template_it->second;
4163  render_to(*output_stream, *parent_template, *json_input, &json_additional_data);
4164  break_rendering = true;
4165  } else if (config.throw_at_missing_includes) {
4166  throw_renderer_error("extends '" + node.file + "' not found", node);
4167  }
4168  }
4169 
4170  void visit(const BlockStatementNode& node) {
4171  const size_t old_level = current_level;
4172  current_level = 0;
4173  current_template = template_stack.front();
4174  const auto block_it = current_template->block_storage.find(node.name);
4175  if (block_it != current_template->block_storage.end()) {
4176  block_statement_stack.emplace_back(&node);
4177  block_it->second->block.accept(*this);
4178  block_statement_stack.pop_back();
4179  }
4180  current_level = old_level;
4181  current_template = template_stack.back();
4182  }
4183 
4184  void visit(const SetStatementNode& node) {
4185  std::string ptr = node.key;
4186  replace_substring(ptr, ".", "/");
4187  ptr = "/" + ptr;
4188  json_additional_data[nlohmann::json::json_pointer(ptr)] = *eval_expression_list(node.expression);
4189  }
4190 
4191 public:
4192  Renderer(const RenderConfig& config, const TemplateStorage &template_storage, const FunctionStorage &function_storage)
4193  : config(config), template_storage(template_storage), function_storage(function_storage) { }
4194 
4195  void render_to(std::ostream &os, const Template &tmpl, const json &data, json *loop_data = nullptr) {
4196  output_stream = &os;
4197  current_template = &tmpl;
4198  json_input = &data;
4199  if (loop_data) {
4200  json_additional_data = *loop_data;
4201  current_loop_data = &json_additional_data["loop"];
4202  }
4203 
4204  template_stack.emplace_back(current_template);
4205  current_template->root.accept(*this);
4206 
4207  json_tmp_stack.clear();
4208  }
4209 };
4210 
4211 } // namespace inja
4212 
4213 #endif // INCLUDE_INJA_RENDERER_HPP_
4214 
4215 // #include "string_view.hpp"
4216 
4217 // #include "template.hpp"
4218 
4219 // #include "utils.hpp"
4220 
4221 
4222 namespace inja {
4223 
4224 using json = nlohmann::json;
4225 
4230  std::string input_path;
4231  std::string output_path;
4232 
4233  LexerConfig lexer_config;
4234  ParserConfig parser_config;
4235  RenderConfig render_config;
4236 
4239 
4240 public:
4242 
4243  explicit Environment(const std::string &global_path) : input_path(global_path), output_path(global_path) {}
4244 
4245  Environment(const std::string &input_path, const std::string &output_path)
4246  : input_path(input_path), output_path(output_path) {}
4247 
4249  void set_statement(const std::string &open, const std::string &close) {
4250  lexer_config.statement_open = open;
4251  lexer_config.statement_open_no_lstrip = open + "+";
4252  lexer_config.statement_open_force_lstrip = open + "-";
4253  lexer_config.statement_close = close;
4254  lexer_config.statement_close_force_rstrip = "-" + close;
4255  lexer_config.update_open_chars();
4256  }
4257 
4259  void set_line_statement(const std::string &open) {
4260  lexer_config.line_statement = open;
4261  lexer_config.update_open_chars();
4262  }
4263 
4265  void set_expression(const std::string &open, const std::string &close) {
4266  lexer_config.expression_open = open;
4267  lexer_config.expression_open_force_lstrip = open + "-";
4268  lexer_config.expression_close = close;
4269  lexer_config.expression_close_force_rstrip = "-" + close;
4270  lexer_config.update_open_chars();
4271  }
4272 
4274  void set_comment(const std::string &open, const std::string &close) {
4275  lexer_config.comment_open = open;
4276  lexer_config.comment_open_force_lstrip = open + "-";
4277  lexer_config.comment_close = close;
4278  lexer_config.comment_close_force_rstrip = "-" + close;
4279  lexer_config.update_open_chars();
4280  }
4281 
4283  void set_trim_blocks(bool trim_blocks) {
4284  lexer_config.trim_blocks = trim_blocks;
4285  }
4286 
4288  void set_lstrip_blocks(bool lstrip_blocks) {
4289  lexer_config.lstrip_blocks = lstrip_blocks;
4290  }
4291 
4293  void set_search_included_templates_in_files(bool search_in_files) {
4294  parser_config.search_included_templates_in_files = search_in_files;
4295  }
4296 
4298  void set_throw_at_missing_includes(bool will_throw) {
4299  render_config.throw_at_missing_includes = will_throw;
4300  }
4301 
4302  Template parse(nonstd::string_view input) {
4303  Parser parser(parser_config, lexer_config, template_storage, function_storage);
4304  return parser.parse(input);
4305  }
4306 
4307  Template parse_template(const std::string &filename) {
4308  Parser parser(parser_config, lexer_config, template_storage, function_storage);
4309  auto result = Template(parser.load_file(input_path + static_cast<std::string>(filename)));
4310  parser.parse_into_template(result, input_path + static_cast<std::string>(filename));
4311  return result;
4312  }
4313 
4314  Template parse_file(const std::string &filename) {
4315  return parse_template(filename);
4316  }
4317 
4318  std::string render(nonstd::string_view input, const json &data) { return render(parse(input), data); }
4319 
4320  std::string render(const Template &tmpl, const json &data) {
4321  std::stringstream os;
4322  render_to(os, tmpl, data);
4323  return os.str();
4324  }
4325 
4326  std::string render_file(const std::string &filename, const json &data) {
4327  return render(parse_template(filename), data);
4328  }
4329 
4330  std::string render_file_with_json_file(const std::string &filename, const std::string &filename_data) {
4331  const json data = load_json(filename_data);
4332  return render_file(filename, data);
4333  }
4334 
4335  void write(const std::string &filename, const json &data, const std::string &filename_out) {
4336  std::ofstream file(output_path + filename_out);
4337  file << render_file(filename, data);
4338  file.close();
4339  }
4340 
4341  void write(const Template &temp, const json &data, const std::string &filename_out) {
4342  std::ofstream file(output_path + filename_out);
4343  file << render(temp, data);
4344  file.close();
4345  }
4346 
4347  void write_with_json_file(const std::string &filename, const std::string &filename_data,
4348  const std::string &filename_out) {
4349  const json data = load_json(filename_data);
4350  write(filename, data, filename_out);
4351  }
4352 
4353  void write_with_json_file(const Template &temp, const std::string &filename_data, const std::string &filename_out) {
4354  const json data = load_json(filename_data);
4355  write(temp, data, filename_out);
4356  }
4357 
4358  std::ostream &render_to(std::ostream &os, const Template &tmpl, const json &data) {
4359  Renderer(render_config, template_storage, function_storage).render_to(os, tmpl, data);
4360  return os;
4361  }
4362 
4363  std::string load_file(const std::string &filename) {
4364  Parser parser(parser_config, lexer_config, template_storage, function_storage);
4365  return parser.load_file(input_path + filename);
4366  }
4367 
4368  json load_json(const std::string &filename) {
4369  std::ifstream file;
4370  open_file_or_throw(input_path + filename, file);
4371  json j;
4372  file >> j;
4373  return j;
4374  }
4375 
4379  void add_callback(const std::string &name, const CallbackFunction &callback) {
4380  add_callback(name, -1, callback);
4381  }
4382 
4386  void add_void_callback(const std::string &name, const VoidCallbackFunction &callback) {
4387  add_void_callback(name, -1, callback);
4388  }
4389 
4393  void add_callback(const std::string &name, int num_args, const CallbackFunction &callback) {
4394  function_storage.add_callback(name, num_args, callback);
4395  }
4396 
4400  void add_void_callback(const std::string &name, int num_args, const VoidCallbackFunction &callback) {
4401  function_storage.add_callback(name, num_args, [callback](Arguments& args) { callback(args); return json(); });
4402  }
4403 
4408  void include_template(const std::string &name, const Template &tmpl) {
4409  template_storage[name] = tmpl;
4410  }
4411 };
4412 
4416 inline std::string render(nonstd::string_view input, const json &data) {
4417  return Environment().render(input, data);
4418 }
4419 
4423 inline void render_to(std::ostream &os, nonstd::string_view input, const json &data) {
4424  Environment env;
4425  env.render_to(os, env.parse(input), data);
4426 }
4427 
4428 } // namespace inja
4429 
4430 #endif // INCLUDE_INJA_ENVIRONMENT_HPP_
4431 
4432 // #include "exceptions.hpp"
4433 
4434 // #include "parser.hpp"
4435 
4436 // #include "renderer.hpp"
4437 
4438 // #include "string_view.hpp"
4439 
4440 // #include "template.hpp"
4441 
4442 
4443 #endif // INCLUDE_INJA_INJA_HPP_
inja::Environment::load_file
std::string load_file(const std::string &filename)
Definition: inja.hpp:4363
inja::Renderer::visit
void visit(const IfStatementNode &node)
Definition: inja.hpp:4140
inja::render_to
void render_to(std::ostream &os, nonstd::string_view input, const json &data)
render with default settings to the given output stream
Definition: inja.hpp:4423
inja::Renderer::visit
void visit(const IncludeStatementNode &node)
Definition: inja.hpp:4149
npc_dialog.location
string location
Definition: npc_dialog.py:49
inja::RenderError::RenderError
RenderError(const std::string &message, SourceLocation location)
Definition: inja.hpp:1746
inja::Renderer::output_stream
std::ostream * output_stream
Definition: inja.hpp:3532
inja::StatisticsVisitor::StatisticsVisitor
StatisticsVisitor()
Definition: inja.hpp:2822
inja::Lexer::pos
size_t pos
Definition: inja.hpp:1971
inja::BlockNode
Definition: inja.hpp:2435
inja::Renderer::config
const RenderConfig config
Definition: inja.hpp:3522
castle_read.prefix
string prefix
Definition: castle_read.py:31
nlohmann::detail::hash
std::size_t hash(const BasicJsonType &j)
hash a JSON value
Definition: json.hpp:5197
inja::Environment::add_void_callback
void add_void_callback(const std::string &name, int num_args, const VoidCallbackFunction &callback)
Adds a void callback with given number or arguments.
Definition: inja.hpp:4400
inja::Environment::write
void write(const Template &temp, const json &data, const std::string &filename_out)
Definition: inja.hpp:4341
inja::FunctionNode::operation
Op operation
Definition: inja.hpp:2512
inja::ExtendsStatementNode::file
const std::string file
Definition: inja.hpp:2703
inja::Token::Token
constexpr Token(Kind kind, nonstd::string_view text)
Definition: inja.hpp:1830
inja::IncludeStatementNode::file
const std::string file
Definition: inja.hpp:2692
inja::FunctionStorage::FunctionData::operation
const Operation operation
Definition: inja.hpp:1630
inja::Renderer::eval_expression_list
const std::shared_ptr< json > eval_expression_list(const ExpressionListNode &expression_list)
Definition: inja.hpp:3565
inja::Token
Helper-class for the inja Lexer.
Definition: inja.hpp:1787
inja::SourceLocation::line
size_t line
Definition: inja.hpp:1722
inja::ForObjectStatementNode::ForObjectStatementNode
ForObjectStatementNode(const std::string &key, const std::string &value, BlockNode *const parent, size_t pos)
Definition: inja.hpp:2665
inja::Parser::parse
Template parse(nonstd::string_view input, nonstd::string_view path)
Definition: inja.hpp:3461
inja::ForObjectStatementNode::value
const std::string value
Definition: inja.hpp:2663
inja::StatisticsVisitor::visit
void visit(const FunctionNode &node)
Definition: inja.hpp:2780
inja::Lexer::minus_state
MinusState minus_state
Definition: inja.hpp:1968
inja::Renderer::block_statement_stack
std::vector< const BlockStatementNode * > block_statement_stack
Definition: inja.hpp:3529
inja::StatisticsVisitor::visit
void visit(const ExpressionListNode &node)
Definition: inja.hpp:2786
inja::ParserError::ParserError
ParserError(const std::string &message, SourceLocation location)
Definition: inja.hpp:1742
inja::Renderer
Class for rendering a Template with data.
Definition: inja.hpp:3519
inja::Renderer::visit
void visit(const JsonNode &node)
Definition: inja.hpp:3678
inja::Renderer::not_found_stack
std::stack< const JsonNode * > not_found_stack
Definition: inja.hpp:3539
inja::Environment::include_template
void include_template(const std::string &name, const Template &tmpl)
Definition: inja.hpp:4408
inja::Template::block_storage
std::map< std::string, std::shared_ptr< BlockStatementNode > > block_storage
Definition: inja.hpp:2839
inja::FunctionNode::number_args
int number_args
Definition: inja.hpp:2515
nlohmann::json
basic_json<> json
default JSON class
Definition: json.hpp:3404
nssv_constexpr
#define nssv_constexpr
Definition: inja.hpp:363
CFBank.open
def open()
Definition: CFBank.py:69
inja::Renderer::get_arguments
std::array< const json *, N > get_arguments(const FunctionNode &node)
Definition: inja.hpp:3600
inja::Environment::lexer_config
LexerConfig lexer_config
Definition: inja.hpp:4233
inja::Parser::parse_statement
bool parse_statement(Template &tmpl, Token::Kind closing, nonstd::string_view path)
Definition: inja.hpp:3189
nlohmann::basic_json::json_pointer
::nlohmann::json_pointer< basic_json > json_pointer
JSON Pointer, see nlohmann::json_pointer.
Definition: json.hpp:17620
inja::ForStatementNode::condition
ExpressionListNode condition
Definition: inja.hpp:2640
c
static event_registration c
Definition: citylife.cpp:425
inja::Lexer::State
State
Definition: inja.hpp:1944
disinfect.a
a
Definition: disinfect.py:13
inja::ExpressionListNode::ExpressionListNode
ExpressionListNode()
Definition: inja.hpp:2623
inja::Renderer::throw_renderer_error
void throw_renderer_error(const std::string &message, const AstNode &node)
Definition: inja.hpp:3594
inja::Renderer::visit
void visit(const BlockNode &node)
Definition: inja.hpp:3658
inja::Parser::parse_expression
bool parse_expression(Template &tmpl, Token::Kind closing)
Definition: inja.hpp:2948
inja::StatisticsVisitor::visit
void visit(const SetStatementNode &)
Definition: inja.hpp:2817
inja::Environment::Environment
Environment(const std::string &input_path, const std::string &output_path)
Definition: inja.hpp:4245
nlohmann::basic_json::value
ValueType value(const typename object_t::key_type &key, const ValueType &default_value) const
access specified object element with default value
Definition: json.hpp:21345
inja::Environment::render
std::string render(nonstd::string_view input, const json &data)
Definition: inja.hpp:4318
inja::Renderer::print_json
void print_json(const std::shared_ptr< json > value)
Definition: inja.hpp:3554
inja::CallbackFunction
std::function< json(Arguments &args)> CallbackFunction
Definition: inja.hpp:1568
inja::IfStatementNode::IfStatementNode
IfStatementNode(bool is_nested, BlockNode *const parent, size_t pos)
Definition: inja.hpp:2683
inja::Lexer::start
void start(nonstd::string_view input)
Definition: inja.hpp:2206
root
static char root[500]
Definition: mapper.cpp:304
inja::Lexer::scan_number
Token scan_number()
Definition: inja.hpp:2121
inja::ExpressionListNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2626
inja::Lexer::scan
Token scan()
Definition: inja.hpp:2219
inja::FunctionNode::precedence
unsigned int precedence
Definition: inja.hpp:2509
inja::FileError
Definition: inja.hpp:1749
inja::Environment::write_with_json_file
void write_with_json_file(const std::string &filename, const std::string &filename_data, const std::string &filename_out)
Definition: inja.hpp:4347
mad_mage_user.file
file
Definition: mad_mage_user.py:15
inja::ForStatementNode
Definition: inja.hpp:2638
inja::Lexer::current_position
SourceLocation current_position() const
Definition: inja.hpp:2202
inja::Parser::add_operator
void add_operator()
Definition: inja.hpp:2921
inja::StatisticsVisitor::visit
void visit(const JsonNode &)
Definition: inja.hpp:2776
inja::FunctionNode::associativity
Associativity associativity
Definition: inja.hpp:2510
arch2xml.escape
def escape(esc_me)
Definition: arch2xml.py:58
inja::FunctionNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2614
inja::IfStatementNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2685
inja::SetStatementNode::expression
ExpressionListNode expression
Definition: inja.hpp:2728
tolower
#define tolower(C)
Definition: c_new.cpp:30
inja::Environment::input_path
std::string input_path
Definition: inja.hpp:4230
inja::Lexer::MinusState
MinusState
Definition: inja.hpp:1960
inja::FileError::FileError
FileError(const std::string &message)
Definition: inja.hpp:1750
Ice.tmp
int tmp
Definition: Ice.py:207
inja::Template::content
std::string content
Definition: inja.hpp:2838
inja::Template
The main inja Template.
Definition: inja.hpp:2836
nlohmann::json_pointer
JSON Pointer.
Definition: json.hpp:3394
inja::Lexer::make_token
Token make_token(Token::Kind kind) const
Definition: inja.hpp:2154
inja::ExpressionNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2461
inja::FunctionNode::FunctionNode
FunctionNode(nonstd::string_view name, size_t pos)
Definition: inja.hpp:2519
inja::Environment::add_void_callback
void add_void_callback(const std::string &name, const VoidCallbackFunction &callback)
Adds a variadic void callback.
Definition: inja.hpp:4386
inja::FileError::FileError
FileError(const std::string &message, SourceLocation location)
Definition: inja.hpp:1751
npc_dialog.filename
filename
Definition: npc_dialog.py:99
inja::ForStatementNode::body
BlockNode body
Definition: inja.hpp:2641
inja::BlockStatementNode::parent
BlockNode *const parent
Definition: inja.hpp:2716
inja::Parser::arguments
std::vector< std::shared_ptr< ExpressionNode > > arguments
Definition: inja.hpp:2889
nlohmann::basic_json::empty
bool empty() const noexcept
checks whether the container is empty.
Definition: json.hpp:22491
inja::Parser::if_statement_stack
std::stack< IfStatementNode * > if_statement_stack
Definition: inja.hpp:2892
inja::Renderer::visit
void visit(const ExpressionListNode &node)
Definition: inja.hpp:4054
inja::string_view::slice
nonstd::string_view slice(nonstd::string_view view, size_t start, size_t end)
Definition: inja.hpp:1880
inja::Template::Template
Template()
Definition: inja.hpp:2841
inja::Environment
Class for changing the configuration.
Definition: inja.hpp:4229
inja::Parser::config
const ParserConfig & config
Definition: inja.hpp:2871
inja::InjaError::InjaError
InjaError(const std::string &type, const std::string &message)
Definition: inja.hpp:1732
inja::Environment::parser_config
ParserConfig parser_config
Definition: inja.hpp:4234
inja::Lexer::config
const LexerConfig & config
Definition: inja.hpp:1965
inja::JsonNode
Definition: inja.hpp:2477
inja::IncludeStatementNode
Definition: inja.hpp:2690
nssv_inline_ns
#define nssv_inline_ns
Definition: inja.hpp:381
inja::FunctionNode::arguments
std::vector< std::shared_ptr< ExpressionNode > > arguments
Definition: inja.hpp:2516
inja::BlockStatementNode::name
const std::string name
Definition: inja.hpp:2714
inja::Renderer::visit
void visit(const ExtendsStatementNode &node)
Definition: inja.hpp:4159
inja::JsonNode::convert_dot_to_json_ptr
static std::string convert_dot_to_json_ptr(nonstd::string_view ptr_name)
Definition: inja.hpp:2482
inja::BlockNode::BlockNode
BlockNode()
Definition: inja.hpp:2439
inja::ForArrayStatementNode::value
const std::string value
Definition: inja.hpp:2651
inja::LiteralNode
Definition: inja.hpp:2466
inja::InjaError::location
const SourceLocation location
Definition: inja.hpp:1730
inja::Parser::load_file
std::string load_file(nonstd::string_view filename)
Definition: inja.hpp:3479
inja::Renderer::json_tmp_stack
std::vector< std::shared_ptr< json > > json_tmp_stack
Definition: inja.hpp:3537
inja::ForObjectStatementNode
Definition: inja.hpp:2660
inja::FunctionNode::FunctionNode
FunctionNode(Op operation, size_t pos)
Definition: inja.hpp:2520
inja::string_view::starts_with
bool starts_with(nonstd::string_view view, nonstd::string_view prefix)
Definition: inja.hpp:1894
inja::FunctionStorage
Class for builtin functions and user-defined callbacks.
Definition: inja.hpp:1574
inja::Renderer::template_stack
std::vector< const Template * > template_stack
Definition: inja.hpp:3528
inja::Renderer::render_to
void render_to(std::ostream &os, const Template &tmpl, const json &data, json *loop_data=nullptr)
Definition: inja.hpp:4195
inja::Parser::parse_into
void parse_into(Template &tmpl, nonstd::string_view path)
Definition: inja.hpp:3391
inja::Parser::block_statement_stack
std::stack< BlockStatementNode * > block_statement_stack
Definition: inja.hpp:2894
inja::BlockStatementNode
Definition: inja.hpp:2712
inja::Renderer::visit
void visit(const SetStatementNode &node)
Definition: inja.hpp:4184
inja::Environment::render_file
std::string render_file(const std::string &filename, const json &data)
Definition: inja.hpp:4326
inja::Renderer::current_template
const Template * current_template
Definition: inja.hpp:3526
INJA_THROW
#define INJA_THROW(exception)
Definition: inja.hpp:37
inja::Environment::render_to
std::ostream & render_to(std::ostream &os, const Template &tmpl, const json &data)
Definition: inja.hpp:4358
inja::Parser::tok
Token tok
Definition: inja.hpp:2877
is_valid_types_gen.line
line
Definition: is_valid_types_gen.py:34
inja::Parser::Parser
Parser(const ParserConfig &parser_config, const LexerConfig &lexer_config, TemplateStorage &template_storage, const FunctionStorage &function_storage)
Definition: inja.hpp:3457
inja::ForArrayStatementNode
Definition: inja.hpp:2649
nlohmann::basic_json::number_integer_t
NumberIntegerType number_integer_t
a type for a number (integer)
Definition: json.hpp:18092
inja::InjaError
Definition: inja.hpp:1726
inja::Lexer::clear_final_line_if_whitespace
static nonstd::string_view clear_final_line_if_whitespace(nonstd::string_view text)
Definition: inja.hpp:2184
inja::StatementNode
Definition: inja.hpp:2631
inja::ExpressionListNode
Definition: inja.hpp:2619
make_face_from_files.args
args
Definition: make_face_from_files.py:37
inja::StatisticsVisitor::visit
void visit(const StatementNode &)
Definition: inja.hpp:2790
inja::TextNode::length
const size_t length
Definition: inja.hpp:2448
rotate-tower.result
bool result
Definition: rotate-tower.py:13
make_face_from_files.parser
parser
Definition: make_face_from_files.py:24
inja::BlockStatementNode::block
BlockNode block
Definition: inja.hpp:2715
inja::RenderError
Definition: inja.hpp:1745
inja::IfStatementNode::condition
ExpressionListNode condition
Definition: inja.hpp:2674
inja::JsonNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2495
inja::VoidCallbackFunction
std::function< void(Arguments &args)> VoidCallbackFunction
Definition: inja.hpp:1569
inja::Environment::Environment
Environment()
Definition: inja.hpp:4241
nonstd::sv_lite::to_string_view
basic_string_view< CharT, Traits > to_string_view(std::basic_string< CharT, Traits, Allocator > const &s)
Definition: inja.hpp:1389
inja::Environment::add_callback
void add_callback(const std::string &name, const CallbackFunction &callback)
Adds a variadic callback.
Definition: inja.hpp:4379
inja::Environment::write_with_json_file
void write_with_json_file(const Template &temp, const std::string &filename_data, const std::string &filename_out)
Definition: inja.hpp:4353
inja::SetStatementNode::SetStatementNode
SetStatementNode(const std::string &key, size_t pos)
Definition: inja.hpp:2730
nlohmann::basic_json::string_t
StringType string_t
a type for a string
Definition: json.hpp:17994
make_face_from_files.str
str
Definition: make_face_from_files.py:30
python_init.path
path
Definition: python_init.py:8
inja::Parser::throw_parser_error
void throw_parser_error(const std::string &message)
Definition: inja.hpp:2896
inja::AstNode::pos
size_t pos
Definition: inja.hpp:2428
inja::ForStatementNode::ForStatementNode
ForStatementNode(BlockNode *const parent, size_t pos)
Definition: inja.hpp:2644
inja::JsonError::JsonError
JsonError(const std::string &message, SourceLocation location)
Definition: inja.hpp:1755
inja::TextNode::TextNode
TextNode(size_t pos, size_t length)
Definition: inja.hpp:2450
inja::InjaError::message
const std::string message
Definition: inja.hpp:1728
inja::Environment::output_path
std::string output_path
Definition: inja.hpp:4231
inja::json
nlohmann::json json
Definition: inja.hpp:1565
inja::Environment::template_storage
TemplateStorage template_storage
Definition: inja.hpp:4238
inja::Lexer::tok_start
size_t tok_start
Definition: inja.hpp:1970
inja::ForArrayStatementNode::ForArrayStatementNode
ForArrayStatementNode(const std::string &value, BlockNode *const parent, size_t pos)
Definition: inja.hpp:2653
inja::IfStatementNode::true_statement
BlockNode true_statement
Definition: inja.hpp:2675
inja::SourceLocation::column
size_t column
Definition: inja.hpp:1723
inja::Lexer::state
State state
Definition: inja.hpp:1967
navar-midane_time.data
data
Definition: navar-midane_time.py:11
inja::Renderer::visit
void visit(const ForArrayStatementNode &node)
Definition: inja.hpp:4062
nonstd
Definition: inja.hpp:1362
inja::ExpressionListNode::ExpressionListNode
ExpressionListNode(size_t pos)
Definition: inja.hpp:2624
inja::IfStatementNode::has_false_statement
bool has_false_statement
Definition: inja.hpp:2680
inja::Renderer::visit
void visit(const ExpressionNode &)
Definition: inja.hpp:3672
inja::StatisticsVisitor::visit
void visit(const BlockNode &node)
Definition: inja.hpp:2766
inja::SetStatementNode::key
const std::string key
Definition: inja.hpp:2727
inja::StatisticsVisitor::visit
void visit(const ExpressionNode &)
Definition: inja.hpp:2773
inja::NodeVisitor::visit
virtual void visit(const BlockNode &node)=0
disinfect.count
int count
Definition: disinfect.py:7
say.max
dictionary max
Definition: say.py:148
inja::IfStatementNode::is_nested
const bool is_nested
Definition: inja.hpp:2679
inja::ExpressionNode
Definition: inja.hpp:2457
nlohmann::basic_json::emplace_back
reference emplace_back(Args &&... args)
add an object to an array
Definition: json.hpp:23000
nlohmann::detail::operator<
bool operator<(const value_t lhs, const value_t rhs) noexcept
comparison operator for JSON types
Definition: json.hpp:147
inja::Parser::add_json_literal
void add_json_literal(const char *content_ptr)
Definition: inja.hpp:2916
inja::JsonNode::name
const std::string name
Definition: inja.hpp:2479
inja::IfStatementNode
Definition: inja.hpp:2672
inja::StatisticsVisitor
A class for counting statistics on a Template.
Definition: inja.hpp:2765
nssv_nullptr
#define nssv_nullptr
Definition: inja.hpp:401
empty
const char * empty[]
Definition: check_treasure.cpp:107
inja::SetStatementNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2732
trim
const char * trim(const char *buf)
Definition: readable.cpp:661
inja::Renderer::get_argument_vector
Arguments get_argument_vector(const FunctionNode &node)
Definition: inja.hpp:3631
inja::FunctionNode::callback
CallbackFunction callback
Definition: inja.hpp:2517
inja::NodeVisitor
Definition: inja.hpp:2399
inja::LiteralNode::value
const nlohmann::json value
Definition: inja.hpp:2468
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
inja::StatisticsVisitor::visit
void visit(const IncludeStatementNode &)
Definition: inja.hpp:2809
inja::Lexer
Class for lexing an inja Template.
Definition: inja.hpp:1943
inja::ForObjectStatementNode::key
const std::string key
Definition: inja.hpp:2662
inja::Renderer::visit
void visit(const ForStatementNode &)
Definition: inja.hpp:4060
guild_entry.text
text
Definition: guild_entry.py:40
inja::StatisticsVisitor::visit
void visit(const ForObjectStatementNode &node)
Definition: inja.hpp:2798
inja::Renderer::json_eval_stack
std::stack< const json * > json_eval_stack
Definition: inja.hpp:3538
inja::AstNode::AstNode
AstNode(size_t pos)
Definition: inja.hpp:2430
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2168
nssv_RESTORE_WARNINGS
#define nssv_RESTORE_WARNINGS()
Definition: inja.hpp:455
inja::Environment::add_callback
void add_callback(const std::string &name, int num_args, const CallbackFunction &callback)
Adds a callback with given number or arguments.
Definition: inja.hpp:4393
inja::Lexer::scan_body
Token scan_body(nonstd::string_view close, Token::Kind closeKind, nonstd::string_view close_trim=nonstd::string_view(), bool trim=false)
Definition: inja.hpp:1974
inja::Renderer::template_storage
const TemplateStorage & template_storage
Definition: inja.hpp:3523
inja::Environment::parse
Template parse(nonstd::string_view input)
Definition: inja.hpp:4302
inja::FunctionStorage::FunctionData::FunctionData
FunctionData(const Operation &op, const CallbackFunction &cb=CallbackFunction{})
Definition: inja.hpp:1629
inja::Renderer::visit
void visit(const ForObjectStatementNode &node)
Definition: inja.hpp:4101
inja::Parser::parse_into_template
void parse_into_template(Template &tmpl, nonstd::string_view filename)
Definition: inja.hpp:3471
inja::Environment::set_statement
void set_statement(const std::string &open, const std::string &close)
Sets the opener and closer for template statements.
Definition: inja.hpp:4249
inja::IncludeStatementNode::IncludeStatementNode
IncludeStatementNode(const std::string &file, size_t pos)
Definition: inja.hpp:2694
inja::Renderer::visit
void visit(const FunctionNode &node)
Definition: inja.hpp:3701
inja::Environment::set_trim_blocks
void set_trim_blocks(bool trim_blocks)
Sets whether to remove the first newline after a block.
Definition: inja.hpp:4283
inja::Parser::json_literal_start
nonstd::string_view json_literal_start
Definition: inja.hpp:2884
inja::Template::Template
Template(const std::string &content)
Definition: inja.hpp:2842
inja::JsonNode::JsonNode
JsonNode(nonstd::string_view ptr_name, size_t pos)
Definition: inja.hpp:2493
inja::ExpressionListNode::root
std::shared_ptr< ExpressionNode > root
Definition: inja.hpp:2621
nlohmann::basic_json::contains
bool contains(KeyT &&key) const
check the existence of an element in a JSON object
Definition: json.hpp:21966
diamondslots.message
string message
Definition: diamondslots.py:57
inja::FunctionNode::name
std::string name
Definition: inja.hpp:2514
inja::Parser::parse
Template parse(nonstd::string_view input)
Definition: inja.hpp:3467
Floor.t
t
Definition: Floor.py:62
inja::Environment::function_storage
FunctionStorage function_storage
Definition: inja.hpp:4237
inja::Lexer::m_in
nonstd::string_view m_in
Definition: inja.hpp:1969
inja::Lexer::skip_whitespaces_and_newlines
void skip_whitespaces_and_newlines()
Definition: inja.hpp:2156
inja::BlockStatementNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2720
inja::FunctionStorage::add_callback
void add_callback(nonstd::string_view name, int num_args, const CallbackFunction &callback)
Definition: inja.hpp:1674
inja::Environment::render_file_with_json_file
std::string render_file_with_json_file(const std::string &filename, const std::string &filename_data)
Definition: inja.hpp:4330
json.hpp
inja::Parser::function_storage
const FunctionStorage & function_storage
Definition: inja.hpp:2875
inja::InjaError::InjaError
InjaError(const std::string &type, const std::string &message, SourceLocation location)
Definition: inja.hpp:1735
nssv_nodiscard
#define nssv_nodiscard
Definition: inja.hpp:407
inja::IncludeStatementNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2696
inja::TemplateStorage
std::map< std::string, Template > TemplateStorage
Definition: inja.hpp:2852
nssv_constexpr14
#define nssv_constexpr14
Definition: inja.hpp:369
inja::Environment::set_throw_at_missing_includes
void set_throw_at_missing_includes(bool will_throw)
Sets whether a missing include will throw an error.
Definition: inja.hpp:4298
inja::AstNode
Base node class for the abstract syntax tree (AST).
Definition: inja.hpp:2424
inja::open_file_or_throw
void open_file_or_throw(const std::string &path, std::ifstream &file)
Definition: inja.hpp:1866
sword_of_souls.Int
Int
Definition: sword_of_souls.py:59
inja::FunctionStorage::FunctionData::callback
const CallbackFunction callback
Definition: inja.hpp:1631
inja::StatisticsVisitor::visit
void visit(const ForArrayStatementNode &node)
Definition: inja.hpp:2793
inja::LiteralNode::LiteralNode
LiteralNode(const nlohmann::json &value, size_t pos)
Definition: inja.hpp:2470
inja::Token::kind
Kind kind
Definition: inja.hpp:1826
inja::Environment::write
void write(const std::string &filename, const json &data, const std::string &filename_out)
Definition: inja.hpp:4335
inja::Parser::get_peek_token
void get_peek_token()
Definition: inja.hpp:2909
inja::ForStatementNode::parent
BlockNode *const parent
Definition: inja.hpp:2642
inja::Arguments
std::vector< const json * > Arguments
Definition: inja.hpp:1567
inja::Renderer::json_input
const json * json_input
Definition: inja.hpp:3531
inja::TextNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2452
nlohmann::basic_json
a class to store JSON values
Definition: json.hpp:3380
give.op
op
Definition: give.py:33
nonstd::sv_lite::to_string
std::basic_string< CharT, Traits, Allocator > to_string(basic_string_view< CharT, Traits > v, Allocator const &a)
Definition: inja.hpp:1382
inja::InjaError::type
const std::string type
Definition: inja.hpp:1727
inja::SourceLocation
Definition: inja.hpp:1721
inja::replace_substring
void replace_substring(std::string &s, const std::string &f, const std::string &t)
Definition: inja.hpp:1922
inja::Parser
Class for parsing an inja Template.
Definition: inja.hpp:2870
inja::FunctionStorage::find_function
FunctionData find_function(nonstd::string_view name, int num_args) const
Definition: inja.hpp:1678
convert.dest
dest
Definition: convert.py:25
inja::Parser::lexer
Lexer lexer
Definition: inja.hpp:2873
inja::StatisticsVisitor::variable_counter
unsigned int variable_counter
Definition: inja.hpp:2820
inja::ForObjectStatementNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2667
std
Definition: json.hpp:4494
inja::Environment::set_search_included_templates_in_files
void set_search_included_templates_in_files(bool search_in_files)
Sets the element notation syntax.
Definition: inja.hpp:4293
inja::Lexer::scan_id
Token scan_id()
Definition: inja.hpp:2107
inja::StatisticsVisitor::visit
void visit(const TextNode &)
Definition: inja.hpp:2772
npc_dialog.index
int index
Definition: npc_dialog.py:102
inja::Environment::parse_file
Template parse_file(const std::string &filename)
Definition: inja.hpp:4314
inja::AstNode::~AstNode
virtual ~AstNode()
Definition: inja.hpp:2431
inja::Environment::set_expression
void set_expression(const std::string &open, const std::string &close)
Sets the opener and closer for template expressions.
Definition: inja.hpp:4265
inja::ParserError
Definition: inja.hpp:1741
inja::Token::text
nonstd::string_view text
Definition: inja.hpp:1827
inja::Environment::parse_template
Template parse_template(const std::string &filename)
Definition: inja.hpp:4307
inja::StatisticsVisitor::visit
void visit(const BlockStatementNode &node)
Definition: inja.hpp:2813
inja::Parser::get_next_token
void get_next_token()
Definition: inja.hpp:2900
nlohmann::detail::get
auto get(const nlohmann::detail::iteration_proxy_value< IteratorType > &i) -> decltype(i.key())
Definition: json.hpp:4475
inja::Template::count_variables
int count_variables()
Return number of variables (total number, not distinct ones) in the template.
Definition: inja.hpp:2845
inja::Environment::set_line_statement
void set_line_statement(const std::string &open)
Sets the opener for template line statements.
Definition: inja.hpp:4259
inja::Renderer::visit
void visit(const LiteralNode &node)
Definition: inja.hpp:3674
level
int level
Definition: readable.cpp:1563
inja::StatisticsVisitor::visit
void visit(const LiteralNode &)
Definition: inja.hpp:2774
inja::FunctionNode::Associativity
Associativity
Definition: inja.hpp:2504
inja::Environment::set_comment
void set_comment(const std::string &open, const std::string &close)
Sets the opener and closer for template comments.
Definition: inja.hpp:4274
inja::JsonError
Definition: inja.hpp:1754
inja::Token::Kind
Kind
Definition: inja.hpp:1788
inja::render
std::string render(nonstd::string_view input, const json &data)
render with default settings to a string
Definition: inja.hpp:4416
inja::BlockNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2441
inja::SetStatementNode
Definition: inja.hpp:2725
inja::FunctionStorage::add_builtin
void add_builtin(nonstd::string_view name, int num_args, Operation op)
Definition: inja.hpp:1670
inja::Lexer::Lexer
Lexer(const LexerConfig &config)
Definition: inja.hpp:2200
inja::ExtendsStatementNode
Definition: inja.hpp:2701
inja::Token::describe
std::string describe() const
Definition: inja.hpp:1832
inja::ExtendsStatementNode::ExtendsStatementNode
ExtendsStatementNode(const std::string &file, size_t pos)
Definition: inja.hpp:2705
inja::Parser::template_storage
TemplateStorage & template_storage
Definition: inja.hpp:2874
inja
Definition: inja.hpp:1563
inja::Environment::render_config
RenderConfig render_config
Definition: inja.hpp:4235
inja::TextNode
Definition: inja.hpp:2446
inja::Renderer::visit
void visit(const TextNode &node)
Definition: inja.hpp:3668
nssv_noexcept
#define nssv_noexcept
Definition: inja.hpp:387
inja::Renderer::Renderer
Renderer(const RenderConfig &config, const TemplateStorage &template_storage, const FunctionStorage &function_storage)
Definition: inja.hpp:4192
inja::Environment::Environment
Environment(const std::string &global_path)
Definition: inja.hpp:4243
sword_of_souls.old_level
old_level
Definition: sword_of_souls.py:14
inja::ForArrayStatementNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2655
inja::Lexer::scan_string
Token scan_string()
Definition: inja.hpp:2136
inja::Renderer::visit
void visit(const BlockStatementNode &node)
Definition: inja.hpp:4170
split
static std::vector< std::string > split(const std::string &field, const std::string &by)
Definition: mapper.cpp:2606
inja::Environment::set_lstrip_blocks
void set_lstrip_blocks(bool lstrip_blocks)
Sets whether to strip the spaces and tabs from the start of a line to a block.
Definition: inja.hpp:4288
inja::get_source_location
SourceLocation get_source_location(nonstd::string_view content, size_t pos)
Definition: inja.hpp:1899
inja::StatisticsVisitor::visit
void visit(const ExtendsStatementNode &)
Definition: inja.hpp:2811
inja::JsonNode::ptr
const json::json_pointer ptr
Definition: inja.hpp:2480
inja::FunctionNode
Definition: inja.hpp:2500
inja::IfStatementNode::parent
BlockNode *const parent
Definition: inja.hpp:2677
inja::Renderer::visit
void visit(const StatementNode &)
Definition: inja.hpp:4058
inja::Renderer::function_storage
const FunctionStorage & function_storage
Definition: inja.hpp:3524
inja::ExpressionNode::ExpressionNode
ExpressionNode(size_t pos)
Definition: inja.hpp:2459
inja::Parser::operator_stack
std::stack< std::shared_ptr< FunctionNode > > operator_stack
Definition: inja.hpp:2891
inja::LiteralNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2472
inja::Lexer::get_config
const LexerConfig & get_config() const
Definition: inja.hpp:2354
nssv_DISABLE_MSVC_WARNINGS
#define nssv_DISABLE_MSVC_WARNINGS(codes)
Definition: inja.hpp:445
None
@ None
Definition: land.c:37
inja::Parser::function_stack
std::stack< std::pair< FunctionNode *, size_t > > function_stack
Definition: inja.hpp:2888
inja::StatementNode::StatementNode
StatementNode(size_t pos)
Definition: inja.hpp:2633
guildbuy.temp
def temp
Definition: guildbuy.py:26
altar_valkyrie.accept
def accept(description)
Definition: altar_valkyrie.py:22
dragon.state
state
Definition: dragon.py:84
inja::StatisticsVisitor::visit
void visit(const IfStatementNode &node)
Definition: inja.hpp:2803
inja::FunctionStorage::FunctionData
Definition: inja.hpp:1628
inja::FunctionStorage::Operation
Operation
Definition: inja.hpp:1576
inja::Environment::render
std::string render(const Template &tmpl, const json &data)
Definition: inja.hpp:4320
inja::Renderer::json_additional_data
json json_additional_data
Definition: inja.hpp:3534
inja::ExtendsStatementNode::accept
void accept(NodeVisitor &v) const
Definition: inja.hpp:2707
inja::Parser::for_statement_stack
std::stack< ForStatementNode * > for_statement_stack
Definition: inja.hpp:2893
inja::IfStatementNode::IfStatementNode
IfStatementNode(BlockNode *const parent, size_t pos)
Definition: inja.hpp:2682
inja::Lexer::skip_whitespaces_and_first_newline
void skip_whitespaces_and_first_newline()
Definition: inja.hpp:2164
inja::BlockStatementNode::BlockStatementNode
BlockStatementNode(BlockNode *const parent, const std::string &name, size_t pos)
Definition: inja.hpp:2718
nonstd::sv_lite::to_string
std::basic_string< CharT, Traits > to_string(basic_string_view< CharT, Traits > v)
Definition: inja.hpp:1377
inja::IfStatementNode::false_statement
BlockNode false_statement
Definition: inja.hpp:2676
operator<<
QDataStream & operator<<(QDataStream &out, const CREFilterDefinition &filter)
Definition: CREFilterDefinition.cpp:49
inja::Renderer::truthy
bool truthy(const json *data) const
Definition: inja.hpp:3543
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
inja::Template::root
BlockNode root
Definition: inja.hpp:2837
inja::Parser::add_to_template_storage
void add_to_template_storage(nonstd::string_view path, std::string &template_name)
Definition: inja.hpp:2932
inja::StatisticsVisitor::visit
void visit(const ForStatementNode &)
Definition: inja.hpp:2791
inja::BlockNode::nodes
std::vector< std::shared_ptr< AstNode > > nodes
Definition: inja.hpp:2437
give.name
name
Definition: give.py:27
inja::Environment::load_json
json load_json(const std::string &filename)
Definition: inja.hpp:4368
level
Definition: level.py:1