├── .gitignore ├── INSTALL.md ├── Makefile ├── README.md ├── examples ├── .gitignore ├── Makefile ├── main.cpp └── template.tpl ├── include ├── boolvalue.h ├── buffer.h ├── callback.h ├── callbacks.h ├── compileerror.h ├── data.h ├── datevalue.h ├── doublevalue.h ├── file.h ├── iterator.h ├── mapvalue.h ├── modifier.h ├── nullvalue.h ├── numericvalue.h ├── parameters.h ├── runtimeerror.h ├── source.h ├── state.h ├── stringvalue.h ├── template.h ├── value.h ├── variantvalue.h └── vectorvalue.h ├── program └── main.cpp ├── smarttpl.h ├── src ├── builtin │ ├── base64decode.h │ ├── base64encode.h │ ├── capitalize.h │ ├── cat.h │ ├── count.h │ ├── count_characters.h │ ├── count_paragraphs.h │ ├── count_words.h │ ├── date_format.h │ ├── default.h │ ├── empty.h │ ├── escape.h │ ├── indent.h │ ├── jsondecode.h │ ├── jsonencode.h │ ├── md5.h │ ├── nl2br.h │ ├── number_format.h │ ├── parsedtime.h │ ├── range.h │ ├── regex_replace.h │ ├── replace.h │ ├── sha1.h │ ├── sha256.h │ ├── sha512.h │ ├── spacify.h │ ├── strlen.h │ ├── strpos.h │ ├── strstr.h │ ├── substr.h │ ├── tolower.h │ ├── toupper.h │ ├── trim.h │ ├── truncate.h │ ├── ucfirst.h │ ├── urldecode.h │ └── urlencode.h ├── bytecode.cpp ├── bytecode.h ├── callbacks.cpp ├── callbacks.h ├── callbackvalue.h ├── ccode.cpp ├── ccode.h ├── data.cpp ├── dynamic │ ├── function.h │ ├── handle.h │ ├── library.h │ └── openssl.h ├── errorlabel.h ├── escaper.cpp ├── escaper.h ├── escapers │ ├── base64.h │ ├── html.h │ ├── json.h │ ├── null.h │ └── url.h ├── executor.h ├── expressions │ ├── anonymousvariable.h │ ├── arrayaccess.h │ ├── booleaninverter.h │ ├── expression.h │ ├── filter.h │ ├── literal.h │ ├── literalarrayaccess.h │ ├── literalboolean.h │ ├── literaldouble.h │ ├── literalinteger.h │ ├── literalstring.h │ ├── literalvariable.h │ ├── variable.h │ └── variablearrayaccess.h ├── generator.h ├── handler.h ├── includes.h ├── iterator.h ├── jit_exception.h ├── library.cpp ├── library.h ├── map_iterator.h ├── mapvalue.cpp ├── modifiers │ ├── modifierexpression.h │ ├── modifiers.h │ └── parameters.h ├── operators │ ├── binary.h │ ├── binaryand.h │ ├── binaryarithmetric.h │ ├── binaryboolean.h │ ├── binarycompare.h │ ├── binarydivide.h │ ├── binaryequals.h │ ├── binarygreater.h │ ├── binarygreaterequals.h │ ├── binarylesser.h │ ├── binarylesserequals.h │ ├── binaryminus.h │ ├── binarymodulo.h │ ├── binarymultiply.h │ ├── binarynotequals.h │ ├── binaryor.h │ ├── binaryplus.h │ ├── binaryregex.h │ └── operator.h ├── parser.lemon ├── quotedstring.h ├── signature_callback.h ├── statements │ ├── assign.h │ ├── expression.h │ ├── foreach.h │ ├── if.h │ ├── raw.h │ ├── statement.h │ └── statements.h ├── syntaxtree.h ├── template.cpp ├── token.h ├── tokenizer_v1.flex ├── tokenizer_v1.h ├── tokenizer_v2.flex ├── tokenizer_v2.h ├── tokenprocessor.cpp ├── tokenprocessor.h ├── value.cpp ├── variantvalue.cpp ├── vector_iterator.h └── vectorvalue.cpp └── test ├── .gitignore ├── Makefile ├── callbacks.cpp ├── ccode.cpp ├── ccode.h ├── encoding.cpp ├── invalid_syntax.cpp ├── main.cpp ├── modifier.cpp ├── modifiers.cpp ├── runtime.cpp ├── stress.cpp └── syntax.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | *.so 4 | *.a 5 | *.txt 6 | parser.cpp 7 | parser.h 8 | parser.out 9 | tokenizer_v?.cpp 10 | a.out 11 | smarttpl 12 | 13 | examples/*.c 14 | 15 | .idea/ 16 | cmake-build-debug/ 17 | 18 | 19 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | INSTALL 2 | ======= 3 | 4 | To install SMART-TPL you'll need the following dependencies 5 | 6 | * lemon 7 | * flex 8 | * boost-regex 9 | * openssl 10 | * libjit 11 | * timelib (as shared object file) 12 | 13 | Both lemon and flex can usually be found in your distro repositories. Libjit however is often missing, you clone it from http://git.savannah.gnu.org/cgit/libjit.git/ 14 | Installing it however does require yacc (often packaged as bison), texi2html/texinfo. If libjit is in the repository of your distro you won't need these. 15 | Although use of libjit from your distro repository is probably rather outdated so use of those is discouraged. 16 | 17 | Timelib can be downloaded and installed from https://github.com/CopernicaMarketingSoftware/timelib, from which installing is done by `make` and `make install`. 18 | 19 | After you have all the required dependencies a simple make and make install should be enough. 20 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile template 3 | # 4 | 5 | # 6 | # Compiler and linker 7 | # 8 | 9 | COMPILER = clang++ 10 | LINKER = g++ 11 | COMPILER_FLAGS = -Wall -c -O0 -g -std=c++11 -fpic -o 12 | LINKER_DEPENDENCIES = -lsmarttpl 13 | LINKER_FLAGS = 14 | 15 | # 16 | # Command to remove files, copy files and create directories. 17 | # 18 | 19 | RM = rm -f 20 | CP = cp -f 21 | MKDIR = mkdir -p 22 | 23 | # 24 | # All source files are simply all *.cpp files found in the current directory 25 | # 26 | 27 | SOURCES = $(wildcard *.cpp) 28 | OBJECTS = $(SOURCES:%.cpp=%.o) 29 | 30 | # 31 | # Result file 32 | # 33 | 34 | RESULT = test 35 | 36 | # 37 | # From here the build instructions start 38 | # 39 | 40 | all: ${OBJECTS} ${RESULT} 41 | 42 | ${RESULT}: ${OBJECTS} 43 | ${LINKER} ${LINKER_FLAGS} -o $@ ${OBJECTS} ${LINKER_DEPENDENCIES} 44 | 45 | ${OBJECTS}: 46 | ${COMPILER} ${COMPILER_FLAGS} $@ ${@:%.o=%.cpp} 47 | 48 | clean: 49 | ${RM} ${RESULT} ${OBJECTS} 50 | 51 | -------------------------------------------------------------------------------- /examples/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Main.cpp 3 | * 4 | * Example program that shows how to use a template 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | #include 10 | #include 11 | 12 | /** 13 | * Main function 14 | * @return int 15 | */ 16 | int main(int argc, const char *argv[]) 17 | { 18 | // loop through the arguments 19 | for (int arg = 1; arg < argc; arg++) 20 | { 21 | SmartTpl::File file(argv[arg]); 22 | // create a template object 23 | SmartTpl::Template tpl(file); 24 | 25 | // construct data object 26 | SmartTpl::Data data; 27 | 28 | // assign variables 29 | std::map map; 30 | map["member"] = "Test"; 31 | map["anothermember"] = "Testing 1 2 3.."; 32 | SmartTpl::MapValue mapValue(map); 33 | 34 | SmartTpl::DateValue date("%A %d %B %Y %T"); 35 | data.assignValue("variable", &mapValue) 36 | .callback("name", []() { return "naam"; }) 37 | .assignValue("date", &date) 38 | .assign("x", "Mr. x"); 39 | 40 | // output the template 41 | std::cout << tpl.process(data) << std::endl; 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /examples/template.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {$date} 4 | This is an example template. 5 | 6 | Hello {$name|toupper|tolower|ucfirst}. 7 | 8 | {if true} 9 | And a conditional text 10 | {/if} 11 | {$variable.member} 12 | {foreach $key in $variable} 13 | {$key} 14 | {/foreach} 15 | {if $variable} 16 | sdfsdf 17 | {/if} 18 | 19 | 20 | -------------------------------------------------------------------------------- /include/boolvalue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BoolValue.h 3 | * 4 | * A SmartTpl::Value which represents a boolean 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BoolValue : public Value 19 | { 20 | private: 21 | /** 22 | * The actual boolean value 23 | */ 24 | const bool _value; 25 | 26 | public: 27 | /** 28 | * Constructors 29 | */ 30 | BoolValue(bool value) : _value(value) {} 31 | 32 | /** 33 | * Destructor 34 | */ 35 | virtual ~BoolValue() {} 36 | 37 | /** 38 | * Convert the value to a string 39 | * @return std::string 40 | */ 41 | virtual std::string toString() const override 42 | { 43 | return (_value) ? "true" : "false"; 44 | } 45 | 46 | /** 47 | * Convert the variable to an integer value 48 | * @return integer_t 49 | */ 50 | virtual integer_t toNumeric() const override 51 | { 52 | return _value; 53 | } 54 | 55 | /** 56 | * Convert the variable to a boolean value 57 | * @return bool 58 | */ 59 | virtual bool toBoolean() const override 60 | { 61 | return _value; 62 | } 63 | 64 | /** 65 | * Convert the variable to a floating point value 66 | * @return double 67 | */ 68 | virtual double toDouble() const override 69 | { 70 | return toNumeric(); 71 | } 72 | 73 | /** 74 | * Use this value as index of another parent value 75 | * @param value the value in which to look for this key 76 | * @return VariantValue 77 | */ 78 | virtual VariantValue lookupIn(const Value &value) const override 79 | { 80 | // get member via integer 81 | return value.member(this->toInteger()); 82 | } 83 | }; 84 | 85 | /** 86 | * End namespace 87 | */ 88 | } 89 | -------------------------------------------------------------------------------- /include/buffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Buffer.h 3 | * 4 | * Template source that can be used for templates that are fetched from 5 | * memory. 6 | * 7 | * Explanation: when you instantiate a Template object, you need to pass 8 | * a Source object to it to tell the Template object where it can be found. 9 | * This Buffer class is one of the available Source objects that can be used 10 | * for templates that are already in memory. 11 | * 12 | * Important: the buffer that is passed to the constructor should be valid 13 | * for as long as the Memory object exists! 14 | * 15 | * @author Emiel Bruijntjes 16 | * @copyright 2014 - 2017 Copernica BV 17 | */ 18 | 19 | /** 20 | * Namespace 21 | */ 22 | namespace SmartTpl { 23 | 24 | /** 25 | * Class definition 26 | */ 27 | class Buffer : public Source 28 | { 29 | private: 30 | /** 31 | * The internal buffer 32 | * @var std::string 33 | */ 34 | std::string _buffer; 35 | 36 | public: 37 | /** 38 | * Constructor 39 | * 40 | * @param buffer Pointer to the buffer 41 | * @param size Size of the buffer 42 | * @param version Source code version (2 is more forgiving) 43 | */ 44 | Buffer(const char *buffer, size_t size, size_t version = 1) : Source(version), _buffer(buffer, size) {} 45 | 46 | /** 47 | * Constructor 48 | * 49 | * @param buffer Pointer to the buffer 50 | */ 51 | Buffer(const char *buffer) : Source(1), _buffer(buffer) {} 52 | 53 | /** 54 | * Constructor 55 | * 56 | * @param buffer Create buffer from a std::string 57 | * @param version Source code version (2 is more forgiving) 58 | */ 59 | Buffer(const std::string &buffer, size_t version = 1) : Source(version), _buffer(buffer) {} 60 | Buffer(std::string &&buffer, size_t version = 1) : Source(version), _buffer(std::move(buffer)) {} 61 | 62 | /** 63 | * Destructor 64 | */ 65 | virtual ~Buffer() {} 66 | 67 | /** 68 | * Name of the source 69 | * 70 | * This is the name by which the template is identifier. For file-templates 71 | * this could be the filename, and for templates from other sources this 72 | * could be a different name. 73 | * 74 | * @return const char* 75 | */ 76 | const char *name() const override 77 | { 78 | // an in-memory buffer does not have a variable name, return an empty string instead 79 | return ""; 80 | } 81 | 82 | /** 83 | * Returns a const char* to the start of the buffer, use size() to get the length 84 | * of this buffer. 85 | * 86 | * @return const char* 87 | */ 88 | const char *data() const override 89 | { 90 | // stored in a member 91 | return _buffer.data(); 92 | } 93 | 94 | /** 95 | * Returns the size of the buffer. 96 | * 97 | * @return size_t 98 | */ 99 | size_t size() const override 100 | { 101 | // stored in a member 102 | return _buffer.size(); 103 | } 104 | 105 | /** 106 | * Is the buffer empty 107 | * 108 | * @return bool 109 | */ 110 | bool empty() const 111 | { 112 | // pass on to buffer 113 | return _buffer.empty(); 114 | } 115 | 116 | /** 117 | * Cast the buffer to a string 118 | * @return std::string 119 | */ 120 | operator const std::string&() const 121 | { 122 | return _buffer; 123 | } 124 | }; 125 | 126 | /** 127 | * End namespace 128 | */ 129 | } 130 | -------------------------------------------------------------------------------- /include/callback.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Callback.h 3 | * 4 | * Specific implementation of the Value class, in which the implementation 5 | * is done by a callback 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Include guard 13 | */ 14 | #pragma once 15 | 16 | /** 17 | * Dependencies 18 | */ 19 | #include 20 | 21 | /** 22 | * Set up namespace 23 | */ 24 | namespace SmartTpl { 25 | 26 | /** 27 | * Definition of the callback 28 | */ 29 | using Callback = std::function; 30 | 31 | 32 | /** 33 | * End of namespace 34 | */ 35 | } 36 | -------------------------------------------------------------------------------- /include/compileerror.h: -------------------------------------------------------------------------------- 1 | /** 2 | * CompileError.h 3 | * 4 | * An exception class about compile errors within templates, these will include 5 | * a line number which you can retrieve using the line() method. 6 | * 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Dependencies 12 | */ 13 | #include 14 | 15 | /** 16 | * Namespace 17 | */ 18 | namespace SmartTpl { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class CompileError : public std::runtime_error 24 | { 25 | private: 26 | /** 27 | * The line at which the error occured, no line known means this is set to -1 28 | * @var int 29 | */ 30 | int _line = -1; 31 | 32 | public: 33 | /** 34 | * Constructor 35 | * 36 | * @param error The error message 37 | * @param line The line at which the error occured 38 | */ 39 | CompileError(const std::string &error, int line) 40 | : std::runtime_error("Compile error at line " + std::to_string(line) + ": " + error), _line(line) {}; 41 | CompileError(const std::string &error) 42 | : std::runtime_error("Compile error: " + error) {}; 43 | 44 | /** 45 | * Destructor 46 | */ 47 | virtual ~CompileError() {} 48 | 49 | /** 50 | * The line at which the error occured 51 | * 52 | * @return int 53 | */ 54 | int line() const { return _line; }; 55 | }; 56 | 57 | /** 58 | * End namespace 59 | */ 60 | } -------------------------------------------------------------------------------- /include/doublevalue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * DoubleValue.h 3 | * 4 | * A SmartTpl::Value which represents a floating point type (double) 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class DoubleValue : public Value 19 | { 20 | private: 21 | /** 22 | * The actual double 23 | */ 24 | const double _value; 25 | 26 | public: 27 | /** 28 | * Constructors 29 | */ 30 | DoubleValue(double value) : _value(value) {} 31 | DoubleValue(float value) : _value(value) {} 32 | 33 | /** 34 | * Destructor 35 | */ 36 | virtual ~DoubleValue() {} 37 | 38 | /** 39 | * If this type was used in an arithmetric operation, should it then be 40 | * treated as a floating point number, or as a regular integer? 41 | * @return bool 42 | */ 43 | virtual bool arithmeticFloat() const override 44 | { 45 | // of course double values should be treated as floating point numbers 46 | return true; 47 | } 48 | 49 | /** 50 | * Convert the value to a string 51 | * @return std::string 52 | */ 53 | virtual std::string toString() const override 54 | { 55 | // create buffer 56 | char buffer[512]; 57 | 58 | // format string 59 | size_t written = snprintf(buffer, 512, "%.5f", _value); 60 | 61 | // Remove trailing zeroes 62 | while (buffer[written - 1] == '0') written--; 63 | 64 | // Round number? 65 | if (buffer[written - 1] == '.') written--; 66 | 67 | // Create string object 68 | return std::string(buffer, written); 69 | } 70 | 71 | /** 72 | * Convert the variable to an integer value 73 | * @return integer_t 74 | */ 75 | virtual integer_t toNumeric() const override 76 | { 77 | return _value; 78 | } 79 | 80 | /** 81 | * Convert the variable to a boolean value 82 | * @return bool 83 | */ 84 | virtual bool toBoolean() const override 85 | { 86 | return _value; 87 | } 88 | 89 | /** 90 | * Convert the variable to a floating point value 91 | * @return double 92 | */ 93 | virtual double toDouble() const override 94 | { 95 | return _value; 96 | } 97 | }; 98 | 99 | /** 100 | * End namespace 101 | */ 102 | } 103 | -------------------------------------------------------------------------------- /include/iterator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Iterator.h 3 | * 4 | * Interface that describes an iterator. This class can be extended to create 5 | * iterators for your own value classes. 6 | * 7 | * @author Toon Schoenmakers 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { 15 | 16 | /** 17 | * Forward declarations 18 | */ 19 | class VariantValue; 20 | 21 | /** 22 | * Class definition 23 | */ 24 | class Iterator 25 | { 26 | protected: 27 | /** 28 | * Constructor 29 | * 30 | * The constructor is protected, you should subclass this class instead. 31 | */ 32 | Iterator() {} 33 | 34 | public: 35 | /** 36 | * Destructor 37 | */ 38 | virtual ~Iterator() {}; 39 | 40 | /** 41 | * Check if the iterator is still valid 42 | * @return bool 43 | */ 44 | virtual bool valid() const = 0; 45 | 46 | /** 47 | * Move to the next position 48 | */ 49 | virtual void next() = 0; 50 | 51 | /** 52 | * Retrieve pointer to the current member 53 | * @return Variant 54 | */ 55 | virtual VariantValue value() const = 0; 56 | 57 | /** 58 | * Retrieve a pointer to the current key 59 | * @return Variant 60 | */ 61 | virtual VariantValue key() const = 0; 62 | }; 63 | 64 | /** 65 | * End namespace 66 | */ 67 | } 68 | 69 | -------------------------------------------------------------------------------- /include/modifier.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Modifier.h 3 | * 4 | * Interface that describes a variable modifier. If you want to create your 5 | * own modifiers, you can do so by extending from this modifier base class, 6 | * and implementing the pure virtual functions. 7 | * 8 | * @author Emiel Bruijntjes 9 | * @copyright 2014 Copernica BV 10 | */ 11 | 12 | /** 13 | * Set up namespace 14 | */ 15 | namespace SmartTpl { 16 | 17 | /** 18 | * Class definition 19 | */ 20 | class Modifier 21 | { 22 | public: 23 | /** 24 | * Destructor 25 | */ 26 | virtual ~Modifier() {}; 27 | 28 | /** 29 | * A simple custom exception class which indicates that you do not intend 30 | * to actually modify the input. 31 | */ 32 | class NoModification : public std::exception {}; 33 | 34 | /** 35 | * Modify a variable value, and convert it into a different value 36 | * 37 | * This method is called if the initial value object may not be modified! 38 | * 39 | * @param input Initial value 40 | * @param params Parameters used for this modification 41 | * @return VariantValue A new value object 42 | * @note In case you end up NOT modifying the input, please throw a NoModification 43 | * exception. 44 | */ 45 | virtual VariantValue modify(const Value &input, const Parameters ¶ms) = 0; 46 | }; 47 | 48 | /** 49 | * End namespace 50 | */ 51 | } 52 | 53 | -------------------------------------------------------------------------------- /include/nullvalue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * NullValue.h 3 | * 4 | * A SmartTpl::Value which represents a nullptr 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class NullValue : public Value 19 | { 20 | public: 21 | /** 22 | * Constructors 23 | */ 24 | NullValue() {} 25 | 26 | /** 27 | * Destructor 28 | */ 29 | virtual ~NullValue() {} 30 | 31 | /** 32 | * Use this value as index of another parent value 33 | * @param value the value in which to look for this key 34 | * @return VariantValue 35 | */ 36 | virtual VariantValue lookupIn(const Value &value) const override 37 | { 38 | // it makes no sense to use null to lookup inside another value 39 | return nullptr; 40 | } 41 | }; 42 | 43 | /** 44 | * End namespace 45 | */ 46 | } 47 | -------------------------------------------------------------------------------- /include/numericvalue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * NumericValue.h 3 | * 4 | * A SmartTpl::Value which represents a numeric type (integer_t) 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class NumericValue : public Value 19 | { 20 | private: 21 | /** 22 | * The actual numeric value 23 | * @var integer_t 24 | */ 25 | const integer_t _value; 26 | 27 | public: 28 | /** 29 | * Constructors 30 | */ 31 | NumericValue(int64_t value) : _value(value) {} 32 | NumericValue(int32_t value) : _value(value) {}; 33 | NumericValue(int16_t value) : _value(value) {}; 34 | 35 | /** 36 | * Destructor 37 | */ 38 | virtual ~NumericValue() {} 39 | 40 | /** 41 | * Convert the value to a string 42 | * @return std::string 43 | */ 44 | virtual std::string toString() const override 45 | { 46 | return std::to_string(_value); 47 | } 48 | 49 | /** 50 | * Convert the variable to a numeric value 51 | * @return integer_t 52 | */ 53 | virtual integer_t toNumeric() const override 54 | { 55 | return _value; 56 | } 57 | 58 | /** 59 | * Convert the variable to a boolean value 60 | * @return bool 61 | */ 62 | virtual bool toBoolean() const override 63 | { 64 | return _value; 65 | } 66 | 67 | /** 68 | * Convert the variable to a floating point value 69 | * @return double 70 | */ 71 | virtual double toDouble() const override 72 | { 73 | return toNumeric(); 74 | } 75 | 76 | /** 77 | * Use this value as index of another parent value 78 | * @param value the value in which to look for this key 79 | * @return VariantValue 80 | */ 81 | virtual VariantValue lookupIn(const Value &value) const override 82 | { 83 | // get member via integer 84 | return value.member(this->toInteger()); 85 | } 86 | }; 87 | 88 | /** 89 | * End namespace 90 | */ 91 | } 92 | -------------------------------------------------------------------------------- /include/parameters.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Parameters.h 3 | * 4 | * A container of values that can be passed to the modifiers 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { 14 | 15 | /** 16 | * Internally, the parameters are just a vector of variants 17 | */ 18 | using Parameters = std::vector; 19 | 20 | /** 21 | * End namespace 22 | */ 23 | } -------------------------------------------------------------------------------- /include/runtimeerror.h: -------------------------------------------------------------------------------- 1 | /** 2 | * CompileError.h 3 | * 4 | * An exception class about runtime errors within templates. 5 | * 6 | * @copyright 2014 Copernica BV 7 | */ 8 | 9 | /** 10 | * Dependencies 11 | */ 12 | #include 13 | 14 | /** 15 | * Namespace 16 | */ 17 | namespace SmartTpl { 18 | 19 | /** 20 | * Class definition 21 | */ 22 | class RunTimeError : public std::runtime_error 23 | { 24 | public: 25 | /** 26 | * Constructor 27 | * 28 | * @param error The error message 29 | */ 30 | RunTimeError(const std::string &error) 31 | : std::runtime_error("RunTimeError: " + error) {}; 32 | RunTimeError() : std::runtime_error("RunTimeError") {}; 33 | 34 | /** 35 | * Destructor 36 | */ 37 | virtual ~RunTimeError() {} 38 | }; 39 | 40 | /** 41 | * End namespace 42 | */ 43 | } -------------------------------------------------------------------------------- /include/source.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Source.h 3 | * 4 | * Base class for classes that can fetch a template. There are various 5 | * implementations for this base class: 6 | * 7 | * File File from the local filesystem 8 | * Buffer In-memory buffer holding the template 9 | * 10 | * You can create your own derived classes if you for example want to create 11 | * template that are fetched from a database or from any other source. 12 | * 13 | * @author Emiel Bruijntjes 14 | * @copyright 2014 - 2017 Copernica Marketing Software 15 | */ 16 | 17 | /** 18 | * Namespace 19 | */ 20 | namespace SmartTpl { 21 | 22 | /** 23 | * Class definition 24 | */ 25 | class Source 26 | { 27 | private: 28 | /** 29 | * The source version number 30 | * @var size_t 31 | */ 32 | size_t _version; 33 | 34 | protected: 35 | /** 36 | * Constructor 37 | * 38 | * The constructor is protected, you should create an instance of File, 39 | * Buffer or an implementation of the Source class that you create yourself. 40 | * 41 | * Currently, we support two source versions: 1 and 2. Version 2 is 42 | * more forgiving in parsing standalone curly braces 43 | * 44 | * @param version version number of the source code 45 | */ 46 | Source(size_t version) : _version(version) {} 47 | 48 | public: 49 | /** 50 | * Destructor 51 | */ 52 | virtual ~Source() {} 53 | 54 | /** 55 | * Expose the version number 56 | * @return size_t 57 | */ 58 | size_t version() const { return _version; } 59 | 60 | /** 61 | * Name of the source 62 | * 63 | * This is the name by which the template is identifier. For file-templates 64 | * this could be the filename, and for templates from other sources this 65 | * could be a different name. 66 | * 67 | * @return const char* 68 | */ 69 | virtual const char *name() const = 0; 70 | 71 | /** 72 | * Is this a shared library? 73 | * 74 | * When the source represents a shared library, it means that that it could 75 | * be opened by a call to dlopen(), and it is stored as a .so file on the 76 | * system. The name() method should return the path to the shared library. 77 | * 78 | * @return bool 79 | */ 80 | virtual bool library() const 81 | { 82 | // by default we return false, because this is the most likely 83 | // implementation for almost all source 84 | return false; 85 | } 86 | 87 | /** 88 | * Returns a const char* to the start of the buffer, use size() to get the length 89 | * of this buffer. 90 | * 91 | * @return const char* 92 | */ 93 | virtual const char *data() const = 0; 94 | 95 | /** 96 | * Returns the size of the buffer. 97 | * 98 | * @return size_t 99 | */ 100 | virtual size_t size() const = 0; 101 | 102 | }; 103 | 104 | /** 105 | * End namespace 106 | */ 107 | } 108 | 109 | -------------------------------------------------------------------------------- /include/state.h: -------------------------------------------------------------------------------- 1 | /** 2 | * State.h 3 | * 4 | * The class that implements the "{$smarty} variable that holds the 5 | * current time (and in the future maybe other meta-properties) 6 | * 7 | * @copyright 2018 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Include guard 12 | */ 13 | #pragma once 14 | 15 | /** 16 | * Begin of namespace 17 | */ 18 | namespace SmartTpl { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class State : public Value 24 | { 25 | public: 26 | /** 27 | * Get access to a member value 28 | * @param name name of the member 29 | * @param size size of the name 30 | * @return VariantValue 31 | */ 32 | virtual VariantValue member(const char *name, size_t size) const override 33 | { 34 | // check the member 35 | if (size == 3 && strncmp(name, "now", 3) == 0) return int64_t(time(nullptr)); 36 | 37 | // all other members are not set 38 | return nullptr; 39 | } 40 | }; 41 | 42 | /** 43 | * End of namespace 44 | */ 45 | } 46 | 47 | -------------------------------------------------------------------------------- /include/stringvalue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * StringValue.h 3 | * 4 | * A SmartTpl::Value which represents a string (std::string) 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class StringValue : public Value 19 | { 20 | private: 21 | /** 22 | * The actual string 23 | */ 24 | const std::string _value; 25 | 26 | public: 27 | /** 28 | * Constructors 29 | */ 30 | StringValue(const char* value) : _value(value) {} 31 | StringValue(const char* value, size_t len) : _value(value, len) {}; 32 | StringValue(std::string value) : _value(std::move(value)) {}; 33 | 34 | /** 35 | * Destructor 36 | */ 37 | virtual ~StringValue() {}; 38 | 39 | /** 40 | * Convert the value to a string 41 | * @return std::string 42 | */ 43 | virtual std::string toString() const override 44 | { 45 | return _value; 46 | }; 47 | 48 | /** 49 | * Convert the variable to a numeric value 50 | * @return integer_t 51 | */ 52 | virtual integer_t toNumeric() const override 53 | { 54 | try 55 | { 56 | return std::stoll(_value); 57 | } 58 | catch (...) 59 | { 60 | return 0; 61 | } 62 | }; 63 | 64 | /** 65 | * Convert the variable to a boolean value 66 | * @return bool 67 | */ 68 | virtual bool toBoolean() const override 69 | { 70 | // just like in php an empty string and a string containing "0" are false 71 | if (_value.empty()) return false; 72 | else if (_value == "0") return false; 73 | else return true; 74 | }; 75 | 76 | /** 77 | * Convert the variable to a floating point value 78 | * @return double 79 | */ 80 | virtual double toDouble() const override 81 | { 82 | try 83 | { 84 | return std::stod(_value); 85 | } 86 | catch (...) 87 | { 88 | return 0.0; 89 | } 90 | } 91 | }; 92 | 93 | /** 94 | * End namespace 95 | */ 96 | } 97 | -------------------------------------------------------------------------------- /include/value.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Value.h 3 | * 4 | * Interface that describes a value. This class can be extended to create 5 | * your own custom template variables. 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 - 2019 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { 15 | 16 | /** 17 | * Typedef for a general numeric type, if we ever decide to change it we'll just 18 | * have to modify this. For backwards compatibility, we also support the numeric_t 19 | */ 20 | using integer_t = int64_t; 21 | using numeric_t = integer_t; 22 | 23 | /** 24 | * Forward declaration of VariantValue so we can return VariantValue 25 | */ 26 | class VariantValue; 27 | 28 | /** 29 | * Class definition 30 | */ 31 | class Value 32 | { 33 | public: 34 | /** 35 | * Destructor 36 | */ 37 | virtual ~Value() {}; 38 | 39 | /** 40 | * If this type was used in an arithmetric operation, should it then be 41 | * treated as a floating point number, or as a regular integer? 42 | * @return bool 43 | */ 44 | virtual bool arithmeticFloat() const; 45 | 46 | /** 47 | * Convert the value to a string 48 | * @return std::string 49 | */ 50 | virtual std::string toString() const; 51 | 52 | /** 53 | * Convert the variable to a numeric value (this is a deprecated method) 54 | * @return numeric_t 55 | */ 56 | virtual numeric_t toNumeric() const; 57 | 58 | /** 59 | * Convert the variable to an integer value 60 | * @return integer_t 61 | */ 62 | virtual integer_t toInteger() const; 63 | 64 | /** 65 | * Convert the variable to a boolean value 66 | * @return bool 67 | */ 68 | virtual bool toBoolean() const; 69 | 70 | /** 71 | * Convert the variable to a floating point value 72 | * @return double 73 | */ 74 | virtual double toDouble() const; 75 | 76 | /** 77 | * Get access to the amount of members this value has 78 | * @return size_t 79 | */ 80 | virtual size_t memberCount() const; 81 | 82 | /** 83 | * Get access to a member value 84 | * @param name name of the member 85 | * @param size size of the name 86 | * @return VariantValue 87 | */ 88 | virtual VariantValue member(const char *name, size_t size) const; 89 | 90 | /** 91 | * Get access to a member at a certain position 92 | * @param position Position of the item we want to retrieve 93 | * @return VariantValue 94 | */ 95 | virtual VariantValue member(size_t position) const; 96 | 97 | /** 98 | * Get access to a member at a certain position 99 | * @param position Position of the item we want to retrieve 100 | * @return VariantValue 101 | */ 102 | virtual VariantValue member(const Value &position) const; 103 | 104 | /** 105 | * Use this value as index of another parent value 106 | * @param value the value in which to look for this key 107 | * @return VariantValue 108 | */ 109 | virtual VariantValue lookupIn(const Value &value) const; 110 | 111 | /** 112 | * Create a new iterator that allows you to iterate over the subvalues 113 | * feel free to return nullptr if you don't want to be able to iterate 114 | * over your type 115 | * 116 | * @return Newly allocated Iterator 117 | */ 118 | virtual Iterator *iterator() const; 119 | }; 120 | 121 | /** 122 | * End namespace 123 | */ 124 | } 125 | -------------------------------------------------------------------------------- /smarttpl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SmartTpl.h 3 | * 4 | * This is the startup header file for the SmartTpl library. 5 | * 6 | * SmartTpl is a lightweight template library that is loosely based on the 7 | * "Smarty" template language that is implemented in PHP. SmartTpl is fully 8 | * implemented in C++, and thus much faster. 9 | * 10 | * The SmartTpl language is - although much faster, also not as powerful as 11 | * Smarty. This is on purpose: SmartTpl is a template language, and does not 12 | * want to be a programming language. It can only be used for displaying 13 | * variables in a template, and for simple "if" statements and simple 14 | * loops that iterate over variables. 15 | * 16 | * @author Emiel Bruijntjes 17 | * @copyright 2014 - 2016 Copernica BV 18 | */ 19 | #ifndef __SMART_TPL_H__ 20 | #define __SMART_TPL_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "smarttpl/source.h" 40 | #include "smarttpl/file.h" 41 | #include "smarttpl/buffer.h" 42 | 43 | #include "smarttpl/iterator.h" 44 | 45 | #include "smarttpl/value.h" 46 | #include "smarttpl/variantvalue.h" 47 | #include "smarttpl/nullvalue.h" 48 | #include "smarttpl/boolvalue.h" 49 | #include "smarttpl/numericvalue.h" 50 | #include "smarttpl/doublevalue.h" 51 | #include "smarttpl/stringvalue.h" 52 | #include "smarttpl/vectorvalue.h" 53 | #include "smarttpl/mapvalue.h" 54 | #include "smarttpl/datevalue.h" 55 | 56 | #include "smarttpl/callbacks.h" 57 | #include "smarttpl/parameters.h" 58 | #include "smarttpl/modifier.h" 59 | #include "smarttpl/callback.h" 60 | #include "smarttpl/state.h" 61 | #include "smarttpl/data.h" 62 | #include "smarttpl/template.h" 63 | #include "smarttpl/compileerror.h" 64 | #include "smarttpl/runtimeerror.h" 65 | 66 | /** 67 | * End of the include guard 68 | */ 69 | #endif // __SMART_TPL_H__ 70 | 71 | -------------------------------------------------------------------------------- /src/builtin/base64decode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Base64decode.h 3 | * 4 | * Built-in "|base64_decode" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Base64DecodeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~Base64DecodeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Get the base64 encoder 35 | const Escaper *escaper = Escaper::get("base64"); 36 | 37 | // Turn our input into a string 38 | std::string output(input.toString()); 39 | 40 | // Call decode and return the output 41 | return escaper->decode(output); 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} -------------------------------------------------------------------------------- /src/builtin/base64encode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Base64encode.h 3 | * 4 | * Built-in "|base64_encode" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Base64EncodeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~Base64EncodeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Get the base64 encoder 35 | const Escaper *escaper = Escaper::get("base64"); 36 | 37 | // Turn our input into a string 38 | std::string output(input.toString()); 39 | 40 | // Call encode and return the output 41 | return escaper->encode(output); 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} -------------------------------------------------------------------------------- /src/builtin/capitalize.h: -------------------------------------------------------------------------------- 1 | /** 2 | * capitalize.h 3 | * 4 | * Built-in "|capitaluze:bool" modifier 5 | * 6 | * @author Youri Moll 7 | * @copyright 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class CapitalizeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~CapitalizeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // copy the entire string 35 | std::string output(input.toString()); 36 | 37 | // our delimiters, we will capitalize after any of these characters are encountered 38 | const char* delims = " \t\r\n\f\v"; 39 | 40 | // determine if words with digits will be processed 41 | bool processDigits = false; 42 | 43 | // did the user specify that we should also process words with digits 44 | if (params.size() == 1) processDigits = params[0].toBoolean(); 45 | 46 | // helper variable to determine if a word contains a digit 47 | bool containsDigit = false; 48 | 49 | // We will loop backwards through our input string 50 | for (int i = output.size() - 1; i >= 0; --i) 51 | { 52 | // check if the word we are processing contains a digit 53 | if (isdigit(output[i])) containsDigit = true; 54 | 55 | // if we have found one of our delimiters in the string 56 | if (! strchr(delims, output[i])) continue; 57 | 58 | // Should we skip this word? 59 | if (!processDigits && containsDigit) 60 | { 61 | // we set containsDigit to false 62 | containsDigit = false; 63 | 64 | // and we skip 65 | continue; 66 | } 67 | 68 | // check if the first character of the word is valid and cast it to 69 | // upper case 70 | if (output[i + 1]) output[i + 1] = toupper(output[i + 1]); 71 | 72 | // we set containsDigit to false 73 | containsDigit = false; 74 | } 75 | 76 | // if the fist word contains a digit and we do not want to process those, 77 | // we are done 78 | if (!processDigits && containsDigit) return output; 79 | 80 | // process the first character 81 | output[0] = toupper(output[0]); 82 | 83 | //and return 84 | return output; 85 | } 86 | }; 87 | 88 | /** 89 | * End namespace 90 | */ 91 | }} 92 | -------------------------------------------------------------------------------- /src/builtin/cat.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Cat.h 3 | * 4 | * Built-in "|cat:"string"" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class CatModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~CatModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // copy the entire string 35 | std::string output(input.toString()); 36 | 37 | // Loop through the parameters and add all of them to the output string 38 | for (auto ¶m : params) output.append(param.toString()); 39 | 40 | // return the output 41 | return output; 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} -------------------------------------------------------------------------------- /src/builtin/count.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Count.h 3 | * 4 | * Built-in "|count" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class CountModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~CountModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Simply return the member count 35 | return (int64_t) input.memberCount(); 36 | } 37 | }; 38 | 39 | /** 40 | * End namespace 41 | */ 42 | }} -------------------------------------------------------------------------------- /src/builtin/count_characters.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Count_characters.h 3 | * 4 | * Built-in "|count_characters" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class CountCharactersModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~CountCharactersModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // If we include whitespaces we might as well just return the size 35 | if (params.size() >= 1 && params[0].toBoolean()) return (int64_t) input.toString().size(); 36 | 37 | // Let's just convert our input to a C string 38 | std::string str = input.toString(); 39 | 40 | // Init our output value 41 | integer_t output = 0; 42 | for (auto c : str) { 43 | // Are we not a whitespace? 44 | if (!std::isspace(c)) ++output; 45 | } 46 | 47 | // Return the output 48 | return output; 49 | } 50 | }; 51 | 52 | /** 53 | * End namespace 54 | */ 55 | }} 56 | -------------------------------------------------------------------------------- /src/builtin/count_paragraphs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Count_paragraphs.h 3 | * 4 | * Built-in "|count_paragraphs" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class CountParagraphsModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~CountParagraphsModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Let's just convert our input to a C string 35 | std::string str = input.toString(); 36 | 37 | // Init our output value 38 | integer_t output = 0; 39 | for (auto c : str) 40 | { 41 | // We're really just counting the \n and \r's 42 | if (c == '\n' || c == '\r') ++output; 43 | } 44 | 45 | // Return the output 46 | return output; 47 | } 48 | }; 49 | 50 | /** 51 | * End namespace 52 | */ 53 | }} 54 | -------------------------------------------------------------------------------- /src/builtin/count_words.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Count_words.h 3 | * 4 | * Built-in "|count_words" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class CountWordsModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~CountWordsModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Let's just convert our input to a C string 35 | std::string str(input.toString()); 36 | 37 | // Split our input by whitespaces, newlines, etc 38 | boost::regex rgx("\\s+"); 39 | boost::sregex_token_iterator iter(str.begin(), str.end(), rgx, -1); 40 | 41 | // Init our output value 42 | integer_t output = 0; 43 | 44 | // Count matches that contain alphanumerics 45 | boost::regex word("[a-zA-Z0-9\\x80-\\xff]"); 46 | boost::sregex_token_iterator end; 47 | for (; iter != end; ++iter) 48 | { 49 | if (boost::regex_search(iter->str(), word)) ++output; 50 | } 51 | 52 | // Return the output 53 | return output; 54 | } 55 | }; 56 | 57 | /** 58 | * End namespace 59 | */ 60 | }} 61 | -------------------------------------------------------------------------------- /src/builtin/default.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Default.h 3 | * 4 | * Built-in "|default:"default value"" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class DefaultModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~DefaultModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // convert input to a string 35 | auto value = input.toString(); 36 | 37 | // leap out on non-empty strings 38 | if (!value.empty()) throw NoModification(); 39 | 40 | // input was empty, return the default that was passed as parameter 41 | if (params.size() >= 1) return params[0].toString(); 42 | 43 | // no parameter was given, strange 44 | throw NoModification(); 45 | } 46 | }; 47 | 48 | /** 49 | * End namespace 50 | */ 51 | }} 52 | -------------------------------------------------------------------------------- /src/builtin/empty.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Empty.h 3 | * 4 | * Built-in "|empty" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class EmptyModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~EmptyModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // if our member count is 0 we might be a string 35 | if (input.memberCount() == 0) 36 | { 37 | // as we might be a string we just cast to a string and return empty() of that 38 | std::string str = input.toString(); 39 | return str.empty(); 40 | } 41 | 42 | // if we get here then memberCount was clearly not 0, meaning we are not empty 43 | return false; 44 | } 45 | }; 46 | 47 | /** 48 | * End namespace 49 | */ 50 | }} -------------------------------------------------------------------------------- /src/builtin/escape.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Escape.h 3 | * 4 | * Built-in "|escape:"html"" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class EscapeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~EscapeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // We default to the html encoder 35 | std::string encoder("html"); 36 | 37 | // But if we have at least 1 parameter the first argument is our encoding 38 | if (params.size() >= 1) encoder = params[0].toString(); 39 | 40 | const Escaper *escaper = Escaper::get(encoder); 41 | 42 | // Turn our input into a string 43 | std::string output(input.toString()); 44 | 45 | // Call encode and return the output 46 | return escaper->encode(output); 47 | } 48 | }; 49 | 50 | /** 51 | * End namespace 52 | */ 53 | }} -------------------------------------------------------------------------------- /src/builtin/indent.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Indent.h 3 | * 4 | * Built-in "|indent:1:"\t"" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class IndentModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~IndentModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Initialize the default settings 35 | int indents = 4; 36 | std::string character = " "; 37 | 38 | // if we have any parameters start parsing them 39 | if (params.size() >= 1) 40 | { 41 | indents = params[0].toInteger(); 42 | 43 | // If we have at least 2 parameters use the second one as well 44 | if (params.size() >= 2) character = params[1].toString(); 45 | } 46 | 47 | // initialize our output 48 | std::string output; 49 | 50 | std::string str = input.toString(); 51 | output.reserve(str.size()); 52 | 53 | // Build our final ident 54 | std::string indent; 55 | indent.reserve(indents * character.size()); 56 | for (int i = 0; i < indents; ++i) indent.append(character); 57 | 58 | // prepend the indent to the output 59 | output.append(indent); 60 | 61 | // Loop through all the characters of our input 62 | for (auto c : str) 63 | { 64 | output += c; 65 | 66 | // everytime we hit a new line we append an indent 67 | if (c == '\n') output.append(indent); 68 | } 69 | 70 | // Return the output 71 | return output; 72 | } 73 | }; 74 | 75 | /** 76 | * End namespace 77 | */ 78 | }} 79 | -------------------------------------------------------------------------------- /src/builtin/jsondecode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Jsondecode.h 3 | * 4 | * Built-in "|jsondecode" modifier 5 | * 6 | * @author Michael van der Werve 7 | * @copyright 2020 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class JsondecodeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~JsondecodeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Get the json encoder 35 | const Escaper *escaper = Escaper::get("json"); 36 | 37 | // Turn our input into a string 38 | std::string output(input.toString()); 39 | 40 | // Call encode and return the output 41 | return escaper->decode(output); 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} 49 | -------------------------------------------------------------------------------- /src/builtin/jsonencode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Jsonencode.h 3 | * 4 | * Built-in "|jsonencode" modifier 5 | * 6 | * @author Michael van der Werve 7 | * @copyright 2020 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class JsonencodeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~JsonencodeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Get the json encoder 35 | const Escaper *escaper = Escaper::get("json"); 36 | 37 | // Turn our input into a string 38 | std::string output(input.toString()); 39 | 40 | // Call encode and return the output 41 | return escaper->encode(output); 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} 49 | -------------------------------------------------------------------------------- /src/builtin/md5.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Md5.h 3 | * 4 | * Built-in "|md5" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Dependencies 12 | */ 13 | #include "../dynamic/openssl.h" 14 | 15 | /** 16 | * Namespace 17 | */ 18 | namespace SmartTpl { namespace Internal { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class Md5Modifier : public Modifier 24 | { 25 | public: 26 | /** 27 | * Destructor 28 | */ 29 | virtual ~Md5Modifier() {}; 30 | 31 | /** 32 | * Modify a value object 33 | * @param input 34 | * @param params Parameters used for this modification 35 | * @return Value 36 | */ 37 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 38 | { 39 | // in case we don't have a valid openssl library we are simply returning the original input 40 | if (!OpenSSL::instance()) throw NoModification(); 41 | 42 | // initialize our output 43 | unsigned char digest[MD5_DIGEST_LENGTH]; 44 | 45 | std::string str(input.toString()); 46 | // Call the openssl md5 method 47 | OpenSSL::instance().MD5((unsigned char*) str.c_str(), str.size(), (unsigned char*) &digest); 48 | 49 | std::ostringstream stream; 50 | stream << std::setfill('0') << std::hex; 51 | 52 | for (size_t i = 0; i < sizeof(digest); ++i) stream << std::setw(2) << ((unsigned int) digest[i]); 53 | 54 | // Return our stream as a string 55 | return stream.str(); 56 | } 57 | }; 58 | 59 | /** 60 | * End namespace 61 | */ 62 | }} -------------------------------------------------------------------------------- /src/builtin/nl2br.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Nl2br.h 3 | * 4 | * Built-in "|nl2br" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Nl2brModifier : public ReplaceModifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~Nl2brModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // initialize our output 35 | std::string output(input.toString()); 36 | 37 | // Replace the new lines with
and return 38 | return replace(output, "\n", "
"); 39 | } 40 | }; 41 | 42 | /** 43 | * End namespace 44 | */ 45 | }} -------------------------------------------------------------------------------- /src/builtin/number_format.h: -------------------------------------------------------------------------------- 1 | /** 2 | * NumberFormat.h 3 | * 4 | * Built-in "|number_format" modifier 5 | * 6 | * @author David van Erkelens 7 | * @copyright 2019 - 2020 Copernica BV 8 | */ 9 | 10 | /** 11 | * Dependencies 12 | */ 13 | #include 14 | 15 | /** 16 | * Namespace 17 | */ 18 | namespace SmartTpl { namespace Internal { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class NumberFormatModifier : public Modifier 24 | { 25 | private: 26 | /** 27 | * Struct that works with the std::numpunct facet and can be 28 | * constructed with a char for the decimal and thousands separators 29 | */ 30 | struct formatter : std::numpunct 31 | { 32 | // chars for the separators 33 | char decimal; char thousand; 34 | 35 | // constructor 36 | formatter(char decimal, char thousand) : decimal(decimal), thousand(thousand) {} 37 | 38 | // build in functions for separator formatting 39 | char do_thousands_sep() const { return thousand; } // thousands separator 40 | std::string do_grouping() const { return (int) thousand == 0 ? "" : "\3"; } // separate every 3 digits, if we have a separator 41 | char do_decimal_point() const { return decimal; } // decimal separator 42 | }; 43 | 44 | public: 45 | /** 46 | * Destructor 47 | */ 48 | virtual ~NumberFormatModifier() {}; 49 | 50 | /** 51 | * Modify a value object 52 | * @param input 53 | * @param params Parameters used for this modification 54 | * @return Value 55 | */ 56 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 57 | { 58 | // make sure we have a parameter containing the number of decimals 59 | if (params.size() < 1) throw NoModification(); 60 | 61 | // get the amount of decimals to output 62 | int decimals = params[0].toInteger(); 63 | 64 | // get separator variables for decimals and thousands 65 | char decimal_separator = '.'; char thousand_separator = (char) 0; 66 | 67 | // if we have a valid parameter, overwrite decimal separator 68 | if (params.size() > 1) 69 | { 70 | // convert to string 71 | auto param = params[1].toString(); 72 | 73 | // make sure that we have a character (we could throw if the param is too long?) 74 | if (param.size() > 0) decimal_separator = param[0]; 75 | } 76 | 77 | // if we have a valid parameter, overwrite thousands separator 78 | if (params.size() > 2) 79 | { 80 | // convert to string 81 | auto param = params[2].toString(); 82 | 83 | // make sure that we have a character (we could throw if the param is too long?) 84 | if (param.size() > 0) thousand_separator = param[0]; 85 | } 86 | 87 | // create stringstream to store formatted number 88 | std::stringstream stream; 89 | 90 | // create custom locale for our formatting options 91 | std::locale formatting_locale(stream.getloc(), new NumberFormatModifier::formatter(decimal_separator, thousand_separator)); 92 | 93 | // set formatting options 94 | stream.precision(decimals); 95 | stream.imbue(formatting_locale); 96 | 97 | // stream the value (never in scientific format) 98 | stream << std::fixed << input.toDouble(); 99 | 100 | // create object 101 | return VariantValue(stream.str()); 102 | } 103 | }; 104 | 105 | /** 106 | * End namespace 107 | */ 108 | }} -------------------------------------------------------------------------------- /src/builtin/range.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Range.h 3 | * 4 | * Built-in "|range" modifier, which truncates a list to a certain amount of items 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class RangeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~RangeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // if there are no parameters we're not touching the input 35 | if (params.size() == 0) throw NoModification(); 36 | 37 | // try to retrieve the raw iterator 38 | auto rawIter = input.iterator(); 39 | 40 | // if there's no raw iterator we just return the original input 41 | if (!rawIter) throw NoModification(); 42 | 43 | // get our limits 44 | integer_t begin = 0; 45 | integer_t end = 0; 46 | 47 | // get our limits, if we only have 1 parameter we set that to the end 48 | if (params.size() == 1) end = params[0].toInteger(); 49 | else if (params.size() >= 2) 50 | { 51 | begin = params[0].toInteger(); 52 | end = params[1].toInteger(); 53 | end += begin; 54 | } 55 | 56 | // initialize our output value 57 | std::map output; 58 | 59 | // let's keep a simple counter 60 | integer_t current = 1; 61 | 62 | // loop over all our values 63 | for (std::unique_ptr iter(rawIter); iter->valid(); iter->next(), ++current) 64 | { 65 | // if we're before our start we just continue 66 | if (begin > current) continue; 67 | else if (current > end) break; // if we're past our end we break out 68 | 69 | // and assign to our map 70 | output[iter->key().toString()] = iter->value(); 71 | } 72 | 73 | // simply return our output, it'll be turned into a VariantValue automatically 74 | return output; 75 | } 76 | }; 77 | 78 | /** 79 | * End namespace 80 | */ 81 | }} 82 | -------------------------------------------------------------------------------- /src/builtin/regex_replace.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Regex_Replace.h 3 | * 4 | * Built-in "|regex_replace:"[\r\t\n]":":"" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class RegexReplaceModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~RegexReplaceModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | if (params.size() >= 2) 35 | { 36 | try 37 | { 38 | // initialize our settings based on the provided parameters 39 | boost::regex regex(params[0].toString()); 40 | std::string replace_text(params[1].toString()); 41 | 42 | // initialize our input string 43 | std::string input_str(input.toString()); 44 | 45 | // Do the actual regex replace into stream 46 | std::ostringstream stream; 47 | boost::regex_replace(std::ostream_iterator(stream) 48 | ,input_str.begin(), input_str.end(), regex, replace_text); 49 | 50 | // Turn stream into a string and return it 51 | return stream.str(); 52 | } 53 | catch (const boost::regex_error &error) 54 | { 55 | // Return the original input in case of a failure 56 | throw NoModification(); 57 | } 58 | } 59 | 60 | // Return the original input in case of not enough parameters 61 | throw NoModification(); 62 | } 63 | }; 64 | 65 | /** 66 | * End namespace 67 | */ 68 | }} 69 | -------------------------------------------------------------------------------- /src/builtin/replace.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Replace.h 3 | * 4 | * Built-in "|replace:"\n":"
"" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class ReplaceModifier : public Modifier 19 | { 20 | protected: 21 | /** 22 | * Helper method to find and replace strings in the input buffer 23 | * @param input The input string in which to search and replace 24 | * @param oldStr The string to find and replace 25 | * @param newStr The replacement string 26 | * @return std::string It will return the modified input 27 | */ 28 | std::string &replace(std::string &input, const std::string &oldStr, const std::string &newStr) const 29 | { 30 | size_t pos = 0; 31 | // As long as find doesn't return std::string::npos we found what we were looking for 32 | while ((pos = input.find(oldStr, pos)) != std::string::npos) 33 | { 34 | // Replace that what we were looking for with newStr 35 | input.replace(pos, oldStr.size(), newStr); 36 | pos += newStr.size(); 37 | } 38 | return input; 39 | } 40 | 41 | public: 42 | /** 43 | * Destructor 44 | */ 45 | virtual ~ReplaceModifier() {}; 46 | 47 | /** 48 | * Modify a value object 49 | * @param input 50 | * @param params Parameters used for this modification 51 | * @return Value 52 | */ 53 | virtual VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 54 | { 55 | // initialize our output 56 | std::string output(input.toString()); 57 | 58 | // Check if we have at least 2 parameters 59 | if (params.size() >= 2) 60 | { 61 | // If we do use them to execute the replace 62 | output = replace(output, params[0].toString(), params[1].toString()); 63 | 64 | // Return the modified output 65 | return output; 66 | } 67 | 68 | // Simply return the input 69 | throw NoModification(); 70 | } 71 | }; 72 | 73 | /** 74 | * End namespace 75 | */ 76 | }} -------------------------------------------------------------------------------- /src/builtin/sha1.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Sha1.h 3 | * 4 | * Built-in "|sha1" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Dependencies 12 | */ 13 | #include "../dynamic/openssl.h" 14 | 15 | /** 16 | * Namespace 17 | */ 18 | namespace SmartTpl { namespace Internal { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class Sha1Modifier : public Modifier 24 | { 25 | public: 26 | /** 27 | * Destructor 28 | */ 29 | virtual ~Sha1Modifier() {}; 30 | 31 | /** 32 | * Modify a value object 33 | * @param input 34 | * @param params Parameters used for this modification 35 | * @return Value 36 | */ 37 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 38 | { 39 | // in case we don't have a valid openssl library we are simply returning the original input 40 | if (!OpenSSL::instance()) throw NoModification(); 41 | 42 | // initialize our output 43 | unsigned char digest[SHA_DIGEST_LENGTH]; 44 | 45 | std::string str(input.toString()); 46 | // Call the openssl md5 method 47 | OpenSSL::instance().SHA1((unsigned char*) str.c_str(), str.size(), (unsigned char*) &digest); 48 | 49 | std::ostringstream stream; 50 | stream << std::setfill('0') << std::hex; 51 | 52 | for (size_t i = 0; i < sizeof(digest); ++i) stream << std::setw(2) << ((unsigned int) digest[i]); 53 | 54 | // Return our stream as a string 55 | return stream.str(); 56 | } 57 | }; 58 | 59 | /** 60 | * End namespace 61 | */ 62 | }} -------------------------------------------------------------------------------- /src/builtin/sha256.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Sha256.h 3 | * 4 | * Built-in "|sha256" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Dependencies 12 | */ 13 | #include "../dynamic/openssl.h" 14 | 15 | /** 16 | * Namespace 17 | */ 18 | namespace SmartTpl { namespace Internal { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class Sha256Modifier : public Modifier 24 | { 25 | public: 26 | /** 27 | * Destructor 28 | */ 29 | virtual ~Sha256Modifier() {}; 30 | 31 | /** 32 | * Modify a value object 33 | * @param input 34 | * @param params Parameters used for this modification 35 | * @return Value 36 | */ 37 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 38 | { 39 | // in case we don't have a valid openssl library we are simply returning the original input 40 | if (!OpenSSL::instance()) throw NoModification(); 41 | 42 | // initialize our output 43 | unsigned char digest[SHA256_DIGEST_LENGTH]; 44 | 45 | std::string str(input.toString()); 46 | // Call the openssl md5 method 47 | OpenSSL::instance().SHA256((unsigned char*) str.c_str(), str.size(), (unsigned char*) &digest); 48 | 49 | std::ostringstream stream; 50 | stream << std::setfill('0') << std::hex; 51 | 52 | for (size_t i = 0; i < sizeof(digest); ++i) stream << std::setw(2) << ((unsigned int) digest[i]); 53 | 54 | // Return our stream as a string 55 | return stream.str(); 56 | } 57 | }; 58 | 59 | /** 60 | * End namespace 61 | */ 62 | }} -------------------------------------------------------------------------------- /src/builtin/sha512.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Sha512.h 3 | * 4 | * Built-in "|sha512" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Dependencies 12 | */ 13 | #include "../dynamic/openssl.h" 14 | 15 | /** 16 | * Namespace 17 | */ 18 | namespace SmartTpl { namespace Internal { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class Sha512Modifier : public Modifier 24 | { 25 | public: 26 | /** 27 | * Destructor 28 | */ 29 | virtual ~Sha512Modifier() {}; 30 | 31 | /** 32 | * Modify a value object 33 | * @param input 34 | * @param params Parameters used for this modification 35 | * @return Value 36 | */ 37 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 38 | { 39 | // in case we don't have a valid openssl library we are simply returning the original input 40 | if (!OpenSSL::instance()) throw NoModification(); 41 | 42 | // initialize our output 43 | unsigned char digest[SHA512_DIGEST_LENGTH]; 44 | 45 | std::string str(input.toString()); 46 | // Call the openssl md5 method 47 | OpenSSL::instance().SHA512((unsigned char*) str.c_str(), str.size(), (unsigned char*) &digest); 48 | 49 | std::ostringstream stream; 50 | stream << std::setfill('0') << std::hex; 51 | 52 | for (size_t i = 0; i < sizeof(digest); ++i) stream << std::setw(2) << ((unsigned int) digest[i]); 53 | 54 | // Return our stream as a string 55 | return stream.str(); 56 | } 57 | }; 58 | 59 | /** 60 | * End namespace 61 | */ 62 | }} -------------------------------------------------------------------------------- /src/builtin/spacify.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Spacify.h 3 | * 4 | * Built-in "|spacify" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class SpacifyModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~SpacifyModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // By default we use one space as a seperator 35 | std::string seperator(" "); 36 | 37 | // If we have parameters we have at least one, then this is our custom seperator 38 | if (params.size() >= 1) seperator = params[0].toString(); 39 | 40 | // some of these methods can throw quite hard, which very likely just means there's something wrong with the input 41 | try 42 | { 43 | // Let's just convert our input to a C string 44 | std::string str(input.toString()); 45 | 46 | // Init our output value 47 | std::string output; 48 | 49 | // Reserve the amount of space we'll need which is the original length * (length of seperator + 1) 50 | output.reserve(str.size() * (seperator.length() + 1)); 51 | 52 | for (auto c : str) 53 | { 54 | output += c; 55 | 56 | // append the seperator 57 | output.append(seperator); 58 | } 59 | 60 | // Simply erase the last seperator 61 | output.erase(output.size() - seperator.size()); 62 | 63 | // Return the output 64 | return output; 65 | } 66 | catch (...) 67 | { 68 | // if we failed we simply return the original input 69 | throw NoModification(); 70 | } 71 | } 72 | }; 73 | 74 | /** 75 | * End namespace 76 | */ 77 | }} -------------------------------------------------------------------------------- /src/builtin/strlen.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Strlen.h 3 | * 4 | * Built-in "|strlen" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class StrlenModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~StrlenModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Simply return the length of the toString() method 35 | return (int64_t) input.toString().size(); 36 | } 37 | }; 38 | 39 | /** 40 | * End namespace 41 | */ 42 | }} -------------------------------------------------------------------------------- /src/builtin/strpos.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Strpos.h 3 | * 4 | * Built-in "|strpos:\"needle"" modifier 5 | * 6 | * @author Tamas Elekes 7 | * @copyright 2018 Copernica BV 8 | */ 9 | 10 | /** 11 | * Dependencies 12 | */ 13 | #include 14 | 15 | /** 16 | * Namespace 17 | */ 18 | namespace SmartTpl { namespace Internal { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class StrPosModifier : public Modifier 24 | { 25 | public: 26 | /** 27 | * Destructor 28 | */ 29 | virtual ~StrPosModifier() {}; 30 | 31 | /** 32 | * Modify a value object 33 | * @param input 34 | * @param params Parameters used for this modification 35 | * @return Value 36 | */ 37 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 38 | { 39 | if (params.size() >= 1) 40 | { 41 | // initialize the needle 42 | std::string needle(params[0].toString()); 43 | 44 | // initialize our haystack 45 | std::string haystack(input.toString()); 46 | 47 | // Look for the needle in our haystack 48 | size_t pos = haystack.find(needle); 49 | 50 | // Return -1 if unable to find the needle 51 | if (pos == std::string::npos) return -1; 52 | 53 | // also return -1 if it is outside our indexable range 54 | if (pos > static_cast(std::numeric_limits::max())) return -1; 55 | 56 | // return the position 57 | return static_cast(pos); 58 | } 59 | 60 | // Return the input as we can't do strpos without at least a needle 61 | throw NoModification(); 62 | } 63 | }; 64 | 65 | /** 66 | * End namespace 67 | */ 68 | }} 69 | -------------------------------------------------------------------------------- /src/builtin/strstr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Strstr.h 3 | * 4 | * Built-in "|strstr:\"needle\":true" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class StrStrModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~StrStrModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | if (params.size() >= 1) 35 | { 36 | // initialize the needle and the before_needle flag 37 | std::string needle(params[0].toString()); 38 | bool before_needle = false; 39 | if (params.size() >= 2) before_needle = params[1].toBoolean(); 40 | 41 | // initialize our haystack 42 | std::string haystack(input.toString()); 43 | 44 | // Look for the needle in our haystack 45 | size_t pos = haystack.find(needle); 46 | 47 | // Return nothing (empty value) if we were unable to find the needle 48 | if (pos == std::string::npos) return nullptr; 49 | 50 | if (before_needle) return haystack.substr(0, pos); 51 | else return haystack.substr(pos); 52 | } 53 | 54 | // Return the input as we can't do strstr without at least a needle 55 | throw NoModification(); 56 | } 57 | }; 58 | 59 | /** 60 | * End namespace 61 | */ 62 | }} 63 | -------------------------------------------------------------------------------- /src/builtin/substr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Substr.h 3 | * 4 | * Built-in "|substr:5:5" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class SubStrModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~SubStrModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | if (params.size() >= 1) 35 | { 36 | // initialize our output 37 | std::string output(input.toString()); 38 | 39 | // Turn the second parameter into the substr len parameter 40 | size_t len = std::string::npos; 41 | if (params.size() >= 2) len = params[1].toInteger(); 42 | 43 | try 44 | { 45 | // Execute the substr method on output and return the output of it 46 | return output.substr(params[0].toInteger(), len); 47 | } 48 | catch (const std::out_of_range &error) 49 | { 50 | // In case this happens just fall through so we end up returning the input 51 | } 52 | } 53 | 54 | // Return the input as we can't do substr without parameters 55 | throw NoModification(); 56 | } 57 | }; 58 | 59 | /** 60 | * End namespace 61 | */ 62 | }} 63 | -------------------------------------------------------------------------------- /src/builtin/tolower.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ToLower.h 3 | * 4 | * Built-in "|tolower" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class ToLowerModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~ToLowerModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // copy the entire string 35 | std::string output(input.toString()); 36 | 37 | // convert all the characters to lowercase 38 | for (auto & c : output) c = std::tolower(c); 39 | 40 | // return it wrapped into a new StringValue 41 | return output; 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} -------------------------------------------------------------------------------- /src/builtin/toupper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ToUpper.h 3 | * 4 | * Built-in "|toupper" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class ToUpperModifier : public Modifier { 19 | public: 20 | /** 21 | * Destructor 22 | */ 23 | virtual ~ToUpperModifier() {}; 24 | 25 | /** 26 | * Modify a value object 27 | * @param input 28 | * @param params Parameters used for this modification 29 | * @return Variant 30 | */ 31 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 32 | { 33 | // copy the entire string 34 | std::string output(input.toString()); 35 | 36 | // convert all the characters to uppercase 37 | for (auto & c : output) c = std::toupper(c); 38 | 39 | // return it wrapped into a new StringValue 40 | return output; 41 | } 42 | }; 43 | 44 | /** 45 | * End namespace 46 | */ 47 | }} -------------------------------------------------------------------------------- /src/builtin/trim.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Trim.h 3 | * 4 | * Built-in "|trim:\"to_trim characters\"" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class TrimModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~TrimModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // initialize our characters to trim 35 | std::string to_trim(" \t\n\r\0\x0B"); 36 | if (params.size() >= 1) to_trim = params[0].toString(); 37 | 38 | // initialize our output 39 | std::string output(input.toString()); 40 | 41 | // First we trim the left side 42 | size_t i = output.find_first_not_of(to_trim); 43 | 44 | // If the output of find_first_not_of is 0 it really just means there is nothing to trim at this side 45 | if (i != 0) 46 | { 47 | if (i != std::string::npos) output.erase(0, i); 48 | else output.clear(); 49 | } 50 | 51 | // Now let's trim the right side 52 | i = output.find_last_not_of(to_trim); 53 | 54 | if (i + 1 != output.length()) 55 | { 56 | if (i != std::string::npos) output.erase(i + 1, std::string::npos); 57 | else output.clear(); 58 | } 59 | 60 | // Return the output 61 | return output; 62 | } 63 | }; 64 | 65 | /** 66 | * End namespace 67 | */ 68 | }} -------------------------------------------------------------------------------- /src/builtin/truncate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Truncate.h 3 | * 4 | * Built-in "|truncate:80:"..."" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class TruncateModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~TruncateModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // init our default settings 35 | int length = 80; 36 | std::string etc("..."); 37 | bool break_words = false; 38 | 39 | // Let's parse our parameters 40 | if (params.size() >= 1) 41 | { 42 | // Turn the first parameter into a numeric value 43 | length = params[0].toInteger(); 44 | 45 | // If they requested a length of 0 the output will be "" no matter what 46 | if (length == 0) return ""; 47 | 48 | // Turn the second parameter into the etc field 49 | if (params.size() >= 2) etc = params[1].toString(); 50 | 51 | // Turns the third parameter into the break_words flag 52 | if (params.size() >= 3) break_words = params[2].toBoolean(); 53 | } 54 | 55 | // initialize our output 56 | std::string output(input.toString()); 57 | 58 | // If our input string is longer than our requested output we need to truncate it 59 | if (output.length() > length) 60 | { 61 | // Reduce the length by the length of etc, or itself whatever is shorter 62 | length -= (length < etc.size()) ? length : etc.size(); 63 | 64 | if (!break_words) 65 | { 66 | // As we are not allowed to break words apply some regex magic 67 | // just like smarty does 68 | // https://code.google.com/p/smarty-php/source/browse/branches/Smarty2Dev/libs/plugins/modifier.truncate.php 69 | output = output.substr(0, length + 1); 70 | std::ostringstream stream; 71 | boost::regex_replace(std::ostream_iterator(stream), output.begin(), output.end(), boost::regex("\\s+?(\\S+)?$"), ""); 72 | output = stream.str(); 73 | } 74 | 75 | // Return a substring of length, append etc and return it 76 | return output.substr(0, length) + etc; 77 | } 78 | else 79 | { 80 | // if it isn't we can just return it like this 81 | return output; 82 | } 83 | } 84 | }; 85 | 86 | /** 87 | * End namespace 88 | */ 89 | }} 90 | -------------------------------------------------------------------------------- /src/builtin/ucfirst.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Ucfirst.h 3 | * 4 | * Built-in "|ucfirst" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class UcFirstModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~UcFirstModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // initialize our output 35 | std::string output(input.toString()); 36 | 37 | // in case our input is empty we are just returning our input because that 38 | // is more efficient than returning this new string. Besides in case of an 39 | // empty string calling [0] is undefined behavior.. 40 | if (output.empty()) throw NoModification(); 41 | 42 | // Turn the first character into the uppercase form 43 | output[0] = std::toupper(output[0]); 44 | 45 | // Replace the new lines with
and return 46 | return output; 47 | } 48 | }; 49 | 50 | /** 51 | * End namespace 52 | */ 53 | }} -------------------------------------------------------------------------------- /src/builtin/urldecode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Urldecode.h 3 | * 4 | * Built-in "|urldecode" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class UrldecodeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~UrldecodeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Get the url encoder 35 | const Escaper *escaper = Escaper::get("url"); 36 | 37 | // Turn our input into a string 38 | std::string output(input.toString()); 39 | 40 | // Call encode and return the output 41 | return escaper->decode(output); 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} -------------------------------------------------------------------------------- /src/builtin/urlencode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Urlencode.h 3 | * 4 | * Built-in "|urlencode" modifier 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class UrlencodeModifier : public Modifier 19 | { 20 | public: 21 | /** 22 | * Destructor 23 | */ 24 | virtual ~UrlencodeModifier() {}; 25 | 26 | /** 27 | * Modify a value object 28 | * @param input 29 | * @param params Parameters used for this modification 30 | * @return Value 31 | */ 32 | VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override 33 | { 34 | // Get the url encoder 35 | const Escaper *escaper = Escaper::get("url"); 36 | 37 | // Turn our input into a string 38 | std::string output(input.toString()); 39 | 40 | // Call encode and return the output 41 | return escaper->encode(output); 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} -------------------------------------------------------------------------------- /src/dynamic/handle.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Handle.h 3 | * 4 | * Wrapper around the function handle. Instances of this class are 5 | * stored in shared pointers, so that an instance of the handle 6 | * will stay in memory for as long as there are functions active 7 | * that refer to it. 8 | * 9 | * This is an internal class, in normal circumstances, there is 10 | * no need to instantiate this class. Use the Library class to make 11 | * an instance. 12 | * 13 | * @author Emiel Bruijntjes 14 | * @copyright 2015 Copernica BV 15 | */ 16 | 17 | /** 18 | * Include guard 19 | */ 20 | #pragma once 21 | 22 | /** 23 | * Dependencies 24 | */ 25 | #include 26 | 27 | /** 28 | * Namespace 29 | */ 30 | namespace SmartTpl { namespace Internal { namespace Dynamic { 31 | 32 | /** 33 | * Class definition 34 | */ 35 | class Handle 36 | { 37 | private: 38 | /** 39 | * The actual void* returned from dlopen() 40 | * @var void* 41 | */ 42 | void *_handle; 43 | 44 | public: 45 | /** 46 | * Constructor 47 | * @param name Library to open 48 | */ 49 | Handle(const char *name) : _handle(dlopen(name, RTLD_NOW)) {} 50 | 51 | /** 52 | * Destructor 53 | */ 54 | virtual ~Handle() 55 | { 56 | // close the handle 57 | if (_handle) dlclose(_handle); 58 | } 59 | 60 | /** 61 | * Check whether the handle is valid 62 | * @return bool 63 | */ 64 | bool valid() const 65 | { 66 | // handle should be valid 67 | return _handle != nullptr; 68 | } 69 | 70 | /** 71 | * Get access to the internal handle 72 | * @return void* 73 | */ 74 | void *handle() const 75 | { 76 | return _handle; 77 | } 78 | 79 | /** 80 | * Retrieve a symbol 81 | * @param name 82 | * @return void* 83 | */ 84 | void *symbol(const char *name) const 85 | { 86 | // call dlsym() 87 | return dlsym(_handle, name); 88 | } 89 | }; 90 | 91 | /** 92 | * End namespace 93 | */ 94 | }}} -------------------------------------------------------------------------------- /src/errorlabel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ErrorLabel.h 3 | * 4 | * A grouped label and description for an error 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2018 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class ErrorLabel 19 | { 20 | private: 21 | /** 22 | * Error description 23 | * @var const char * 24 | */ 25 | const char *_message; 26 | 27 | /** 28 | * The label where we can jump to in case of an error 29 | * @var jit_label 30 | */ 31 | jit_label _label; 32 | 33 | public: 34 | /** 35 | * Constructor 36 | * @param function 37 | * @param description 38 | */ 39 | ErrorLabel(jit_function &function, const char *message) : 40 | _message(message), 41 | _label(function.new_label()) {} 42 | 43 | /** 44 | * Forbidden copying 45 | * @param that 46 | */ 47 | ErrorLabel(const ErrorLabel &that) = delete; 48 | 49 | /** 50 | * Destructor 51 | */ 52 | virtual ~ErrorLabel() = default; 53 | 54 | /** 55 | * Get the error message 56 | * @return const char * 57 | */ 58 | const char *message() const { return _message; } 59 | 60 | /** 61 | * Get the label 62 | * @return jib_label 63 | */ 64 | jit_label &label() { return _label; } 65 | }; 66 | 67 | /** 68 | * End of namespace 69 | */ 70 | }} 71 | -------------------------------------------------------------------------------- /src/escaper.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Escaper.cpp 3 | * 4 | * Implementation of the Escaper class 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2020 Copernica BV 8 | */ 9 | 10 | #include "includes.h" 11 | 12 | /** 13 | * Namespace 14 | */ 15 | namespace SmartTpl { namespace Internal { 16 | 17 | /** 18 | * Map which maps the human readable names to the actual escapers 19 | */ 20 | static std::map _escapers; 21 | 22 | /** 23 | * Constructor, the escaper will automatically register itself in _escapers 24 | * @param name The human readable name it should use to register itself 25 | */ 26 | Escaper::Escaper(const char *name) 27 | { 28 | // only register if we have a valid name, this way escapers can prevent to be registered 29 | if (name) _escapers[name] = this; 30 | } 31 | 32 | /** 33 | * Create static instances of all known escapers 34 | */ 35 | static NullEscaper _null; 36 | static HtmlEscaper _html; 37 | static JsonEscaper _json; 38 | static UrlEscaper _url; 39 | static Base64Escaper _base64; 40 | 41 | /** 42 | * Return an Escaper based on the encoding 43 | * @param encoding The human readable name of the Escaper 44 | * @return A new Escape object, which you should manage yourself 45 | */ 46 | Escaper* Escaper::get(const std::string &encoding) 47 | { 48 | // Look for the escaper with name encoding in _escapers 49 | auto iter = _escapers.find(encoding); 50 | 51 | // Did we find it? Yes? Return it 52 | if (iter != _escapers.end()) return iter->second; 53 | 54 | // We didn't find it? That's too bad, let's return the null escaper 55 | return &_null; 56 | } 57 | 58 | /** 59 | * End namespace 60 | */ 61 | }} 62 | -------------------------------------------------------------------------------- /src/escaper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Escaper.h 3 | * 4 | * Base class used to implement encoders and decoders used to encode entire templates 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Escaper 19 | { 20 | protected: 21 | /** 22 | * Protected constructor 23 | */ 24 | Escaper(const char *name); 25 | 26 | /** 27 | * Helper method to find and replace strings in the input buffer 28 | * @param input The input string in which to search and replace 29 | * @param oldStr The string to find and replace 30 | * @param newStr The replacement string 31 | * @return std::string It will return the modified input 32 | */ 33 | std::string &replace(std::string &input, const char *oldStr, const char *newStr) const 34 | { 35 | // First we take the length of both replace strings 36 | const size_t oldStrLen = std::strlen(oldStr); 37 | const size_t newStrLen = std::strlen(newStr); 38 | 39 | size_t pos = 0; 40 | // As long as find doesn't return std::string::npos we found what we were looking for 41 | while ((pos = input.find(oldStr, pos)) != std::string::npos) 42 | { 43 | // Replace that what we were looking for with newStr 44 | input.replace(pos, oldStrLen, newStr, newStrLen); 45 | pos += newStrLen; 46 | } 47 | return input; 48 | } 49 | 50 | public: 51 | /** 52 | * Destructor 53 | */ 54 | virtual ~Escaper() {} 55 | 56 | /** 57 | * Return an Escaper based on the encoding 58 | * @param encoding The human readable name of the Escaper 59 | * @return A static Escaper which you should NOT delete 60 | */ 61 | static Escaper* get(const std::string &encoding); 62 | 63 | /** 64 | * Encode the given input 65 | * It is probably a good idea to directly modify the input instead of making 66 | * a copy and modifying that. 67 | * @param input 68 | */ 69 | virtual std::string &encode(std::string &input) const = 0; 70 | 71 | /** 72 | * Decode the given input 73 | * It is probably a good idea to directly modify the input instead of making 74 | * a copy and modifying that. 75 | * @param input 76 | */ 77 | virtual std::string &decode(std::string &input) const = 0; 78 | 79 | }; 80 | 81 | /** 82 | * End namespace 83 | */ 84 | }} -------------------------------------------------------------------------------- /src/escapers/html.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Html.h 3 | * 4 | * A html en/decoder 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class HtmlEscaper : public Escaper 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | */ 24 | HtmlEscaper() : Escaper("html") {}; 25 | /** 26 | * Destructor 27 | */ 28 | virtual ~HtmlEscaper() {} 29 | 30 | /** 31 | * Encode the given input 32 | * It is probably a good idea to directly modify the input instead of making 33 | * a copy and modifying that. 34 | * @param input 35 | */ 36 | std::string &encode(std::string &input) const override 37 | { 38 | // Replace the <, >, " and & with their escaped versions 39 | // We do this by looping through the input and looking for the characters that need to be escaped at the same time 40 | for (std::string::size_type pos = 0; pos != std::string::npos;) { 41 | 42 | pos = input.find_first_of("\"\'&<>", pos); 43 | 44 | if (pos == std::string::npos) break; 45 | // In case we found one of them we simply replace it in place with the escaped version 46 | switch (input[pos]) 47 | { 48 | case '\"': input.replace(pos, 1, """); pos += 6; break; 49 | case '\'': input.replace(pos, 1, "'"); pos += 6; break; 50 | case '<' : input.replace(pos, 1, "<"); pos += 4; break; 51 | case '>' : input.replace(pos, 1, ">"); pos += 4; break; 52 | case '&' : input.replace(pos, 1, "&"); pos += 5; break; 53 | default: break; 54 | } 55 | } 56 | 57 | // Return the modified input 58 | return input; 59 | } 60 | 61 | /** 62 | * Decode the given input 63 | * It is probably a good idea to directly modify the input instead of making 64 | * a copy and modifying that. 65 | * @param input 66 | */ 67 | std::string &decode(std::string &input) const override 68 | { 69 | // Replace the escaped versions of <, >, " and & with their escaped versions 70 | replace(input, "<", "<"); 71 | replace(input, ">", ">"); 72 | replace(input, """, "\""); 73 | replace(input, "'", "\'"); 74 | replace(input, "&", "&"); 75 | 76 | // Return the modified input 77 | return input; 78 | } 79 | 80 | }; 81 | 82 | /** 83 | * End namespace 84 | */ 85 | }} -------------------------------------------------------------------------------- /src/escapers/null.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Null.h 3 | * 4 | * A null en/decoder, which doesn't modify the input at all 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class NullEscaper : public Escaper 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | */ 24 | NullEscaper() : Escaper("null") {}; 25 | /** 26 | * Destructor 27 | */ 28 | virtual ~NullEscaper() {} 29 | 30 | /** 31 | * Encode the given input 32 | * It is probably a good idea to directly modify the input instead of making 33 | * a copy and modifying that. 34 | * @param input 35 | */ 36 | std::string &encode(std::string &input) const override 37 | { 38 | return input; 39 | } 40 | 41 | /** 42 | * Decode the given input 43 | * It is probably a good idea to directly modify the input instead of making 44 | * a copy and modifying that. 45 | * @param input 46 | */ 47 | std::string &decode(std::string &input) const override 48 | { 49 | return input; 50 | } 51 | 52 | }; 53 | 54 | /** 55 | * End namespace 56 | */ 57 | }} -------------------------------------------------------------------------------- /src/executor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Executor.h 3 | * 4 | * Base class that is used for executing templates. This executor is 5 | * implemented by ByteCode (which compiles a template on the fly) and by 6 | * SharedLibrary (which loads a shared library) 7 | * 8 | * @author Emiel Bruijntjes 9 | * @copyright 2014 Copernica BV 10 | */ 11 | 12 | /** 13 | * Namespace 14 | */ 15 | namespace SmartTpl { namespace Internal { 16 | 17 | /** 18 | * Class definition 19 | */ 20 | class Executor 21 | { 22 | protected: 23 | /** 24 | * Protected constructor 25 | */ 26 | Executor() {} 27 | 28 | public: 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~Executor() {} 33 | 34 | /** 35 | * Execute the template given a certain data source 36 | * @param data 37 | */ 38 | virtual void process(Handler &handler) = 0; 39 | 40 | /** 41 | * Compile the template into C code 42 | * @return std::string 43 | */ 44 | virtual std::string compile() = 0; 45 | 46 | /** 47 | * Retrieve what encoding the 'template' has natively 48 | * @return std::string 49 | */ 50 | virtual std::string encoding() = 0; 51 | 52 | /** 53 | * Does the template use personalisation data? 54 | * 55 | * @return Whether the template uses any personalisation data 56 | */ 57 | virtual bool personalized() const 58 | { 59 | // we assume it does 60 | return true; 61 | } 62 | 63 | }; 64 | 65 | /** 66 | * End namespace 67 | */ 68 | }} 69 | -------------------------------------------------------------------------------- /src/expressions/anonymousvariable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * AnonymousVariable.h 3 | * 4 | * Class that holds a variable that does not have a name but rather is based 5 | * on a literal, so that literals can be treated as variables (e.g. for usage 6 | * with modifiers) 7 | * 8 | * @author David van Erkelens 9 | * @copyright 2019 Copernica BV 10 | */ 11 | 12 | /** 13 | * Set up namespace 14 | */ 15 | namespace SmartTpl { namespace Internal { 16 | 17 | /** 18 | * Class definition 19 | */ 20 | class AnonymousVariable : public Variable 21 | { 22 | private: 23 | /** 24 | * The actual value 25 | * @var std::unique_ptr 26 | */ 27 | std::unique_ptr _value; 28 | 29 | public: 30 | /** 31 | * Create a anonymous variable from a literal 32 | * @param literal 33 | */ 34 | AnonymousVariable(Literal *contents) : _value(contents) {} 35 | 36 | /** 37 | * Destructor 38 | */ 39 | virtual ~AnonymousVariable() {} 40 | 41 | /** 42 | * The return type of the expression (we force a string for the modifiers) 43 | * @return Type 44 | */ 45 | virtual Type type() const override { return Type::String; } 46 | 47 | /** 48 | * Generate the output that leaves a pointer to the variable 49 | * @param generator 50 | */ 51 | virtual void pointer(Generator *generator) const override 52 | { 53 | // generate the code to get a variable pointer to a string 54 | generator->pointerString(_value.get()); 55 | } 56 | }; 57 | 58 | /** 59 | * End of namespace 60 | */ 61 | }} -------------------------------------------------------------------------------- /src/expressions/arrayaccess.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ArrayAccess.h 3 | * 4 | * Class that is used to represent the [] operator to get access to an array 5 | * member 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * Class definition 18 | */ 19 | class ArrayAccess : public Variable 20 | { 21 | protected: 22 | /** 23 | * The underlying variable 24 | * @var Variable 25 | */ 26 | std::unique_ptr _var; 27 | 28 | protected: 29 | /** 30 | * Constructor 31 | * @param variable 32 | */ 33 | ArrayAccess(Variable *variable) : 34 | _var(variable) {} 35 | 36 | public: 37 | /** 38 | * Destructor 39 | */ 40 | virtual ~ArrayAccess() {} 41 | }; 42 | 43 | /** 44 | * End namespace 45 | */ 46 | }} -------------------------------------------------------------------------------- /src/expressions/booleaninverter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryInverter.h 3 | * 4 | * Implementation of the boolean inverter, used to implement the not and ! 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BooleanInverter : public Expression 19 | { 20 | private: 21 | /** 22 | * The expression we're going to invert 23 | * @var Expression 24 | */ 25 | std::unique_ptr _expression; 26 | 27 | public: 28 | /** 29 | * Constructor 30 | * @param expression 31 | */ 32 | BooleanInverter(Expression *expression) : _expression(expression) {} 33 | 34 | /** 35 | * Destructor 36 | */ 37 | virtual ~BooleanInverter() {} 38 | 39 | /** 40 | * The return type of the expression 41 | * @return Type 42 | */ 43 | virtual Type type() const override { return Type::Boolean; }; 44 | 45 | /** 46 | * Generate the instruction 47 | * @param generator 48 | */ 49 | virtual void toBoolean(Generator *generator) const override 50 | { 51 | // create an inverted generator 52 | generator->negateBoolean(_expression.get()); 53 | } 54 | }; 55 | 56 | /** 57 | * End of namespace 58 | */ 59 | }} 60 | -------------------------------------------------------------------------------- /src/expressions/filter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Filter.h 3 | * 4 | * A filter combines a variable with a number of modifiers 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Filter : public Variable 19 | { 20 | private: 21 | /** 22 | * The base expression 23 | * @var Variable 24 | */ 25 | std::unique_ptr _variable; 26 | 27 | /** 28 | * The modifiers that should be applied 29 | * @var Modifiers 30 | */ 31 | std::unique_ptr _modifiers; 32 | 33 | public: 34 | /** 35 | * Constructor 36 | * @param expression 37 | * @param modifiers 38 | */ 39 | Filter(const Variable *variable, const Modifiers *modifiers) : 40 | _variable(variable), _modifiers(modifiers) {} 41 | 42 | /** 43 | * Destructor 44 | */ 45 | virtual ~Filter() = default; 46 | 47 | /** 48 | * The return type of the expression 49 | * @return Type 50 | */ 51 | Type type() const override { return Type::Value; }; 52 | 53 | /** 54 | * Generate the output that leaves a pointer to the variable 55 | * @param generator 56 | */ 57 | virtual void pointer(Generator *generator) const override 58 | { 59 | _modifiers->generate(generator, _variable.get()); 60 | } 61 | 62 | /** 63 | * Generate the expression as string value 64 | * @param generator 65 | */ 66 | virtual void toString(Generator *generator) const override 67 | { 68 | _modifiers->generateString(generator, _variable.get()); 69 | } 70 | 71 | /** 72 | * Generate the expression as a numeric value 73 | * @param generator 74 | */ 75 | virtual void toInteger(Generator *generator) const override 76 | { 77 | throw std::runtime_error("Non-default integer implementation called"); 78 | }; 79 | 80 | /** 81 | * Generate the expression as a double value 82 | * @param generator 83 | */ 84 | virtual void toDouble(Generator *generator) const override 85 | { 86 | _modifiers->generateDouble(generator, _variable.get()); 87 | }; 88 | 89 | /** 90 | * Generate the expression as a boolean value 91 | * @param generator 92 | */ 93 | virtual void toBoolean(Generator *generator) const override 94 | { 95 | _modifiers->generateBoolean(generator, _variable.get()); 96 | }; 97 | 98 | /** 99 | * Retrieve whether we should escape or not, this method will simply check 100 | * for the "raw" modifier 101 | * @return false if we shouldn't escape, true otherwise 102 | */ 103 | bool escape() const 104 | { 105 | // Look for a modifier named "raw" 106 | auto iter = std::find_if(_modifiers->begin(), _modifiers->end() 107 | ,[](const std::unique_ptr &mod) { 108 | return mod->token() == "raw"; 109 | }); 110 | 111 | // Return whether we found the "raw" modifier or not 112 | return iter == _modifiers->end(); 113 | } 114 | 115 | /** 116 | * Generate the expression to output ourself 117 | * @param generator 118 | */ 119 | virtual void output(Generator *generator) const override 120 | { 121 | generator->output(this); 122 | } 123 | }; 124 | 125 | /** 126 | * End namespace 127 | */ 128 | }} 129 | -------------------------------------------------------------------------------- /src/expressions/literal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Literal.h 3 | * 4 | * Base class for expressions that hold a literal value, for example a literal 5 | * integer or literal boolean 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * Class definition 18 | */ 19 | class Literal : public Expression 20 | { 21 | protected: 22 | /** 23 | * Constructor is protected, only derived classes can be instantiated 24 | */ 25 | Literal() {} 26 | 27 | public: 28 | /** 29 | * Destructor 30 | */ 31 | virtual ~Literal() {} 32 | }; 33 | 34 | /** 35 | * End namespace 36 | */ 37 | }} -------------------------------------------------------------------------------- /src/expressions/literalarrayaccess.h: -------------------------------------------------------------------------------- 1 | /** 2 | * LiteralArrayAccess.h 3 | * 4 | * Class that is used to represent the [] operator to get access to an array 5 | * member, when used with a literal string (not an expression) 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * Class definition 18 | */ 19 | class LiteralArrayAccess : public ArrayAccess 20 | { 21 | protected: 22 | /** 23 | * The key that is accessed 24 | * @var std::unique_ptr 25 | */ 26 | std::unique_ptr _key; 27 | 28 | public: 29 | /** 30 | * Constructor 31 | * @param variable 32 | * @param key 33 | */ 34 | LiteralArrayAccess(Variable *variable, Token *token) : 35 | ArrayAccess(variable), 36 | _key(token) {} 37 | 38 | /** 39 | * Destructor 40 | */ 41 | virtual ~LiteralArrayAccess() {} 42 | 43 | /** 44 | * The return type of the expression 45 | * @return Type 46 | */ 47 | Type type() const override { return Type::Value; } 48 | 49 | /** 50 | * Generate a call that creates a pointer to a variable 51 | * @param generator 52 | */ 53 | void pointer(Generator *generator) const override 54 | { 55 | // generate the code to access a member 56 | generator->varPointer(_var.get(), *_key); 57 | } 58 | }; 59 | 60 | /** 61 | * End namespace 62 | */ 63 | }} -------------------------------------------------------------------------------- /src/expressions/literalboolean.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Boolean.h 3 | * 4 | * Implementation of a literal boolean value 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class LiteralBoolean : public Literal 19 | { 20 | private: 21 | /** 22 | * The actual value 23 | * @var bool 24 | */ 25 | const bool _value; 26 | 27 | public: 28 | /** 29 | * Constructor 30 | * @param bool 31 | */ 32 | LiteralBoolean(bool value) : _value(value) {} 33 | 34 | /** 35 | * Destructor 36 | */ 37 | virtual ~LiteralBoolean() {} 38 | 39 | /** 40 | * The return type of the expression 41 | * @return Type 42 | */ 43 | Type type() const override { return Type::Boolean; } 44 | 45 | /** 46 | * Generate the code to get the const char * to the expression 47 | * @param generator 48 | */ 49 | virtual void toString(Generator *generator) const override 50 | { 51 | // create an empty string, booleans have no output 52 | generator->stringValue(""); 53 | } 54 | 55 | /** 56 | * Generate the code to get the boolean value of the expression 57 | * @param generator 58 | */ 59 | virtual void toBoolean(Generator *generator) const override 60 | { 61 | // turn the value into 1 or 0 (in C there are no booleans) 62 | generator->integerValue(_value ? 1 : 0); 63 | } 64 | 65 | /** 66 | * Generate the code to get the integer value of the expression 67 | * @param generator 68 | */ 69 | virtual void toInteger(Generator *generator) const override 70 | { 71 | // turn the value into 1 or 0 (in C there are no booleans) 72 | generator->integerValue(_value ? 1 : 0); 73 | } 74 | 75 | /** 76 | * Generate the expression as a double value 77 | * @param generator 78 | */ 79 | virtual void toDouble(Generator *generator) const override 80 | { 81 | // turn the value into 1 or 0 (in C there are no booleans) 82 | generator->doubleValue(_value ? 1 : 0); 83 | } 84 | 85 | /** 86 | * Generate expression as a pointer to the runtime space 87 | * @param generator 88 | */ 89 | virtual void toPointer(Generator *generator) const override 90 | { 91 | // call the appropriate function in the generator 92 | generator->pointerBoolean(this); 93 | } 94 | }; 95 | 96 | /** 97 | * End namespace 98 | */ 99 | }} 100 | -------------------------------------------------------------------------------- /src/expressions/literaldouble.h: -------------------------------------------------------------------------------- 1 | /** 2 | * LiteralDouble.h 3 | * 4 | * Implementation of a literal integer value 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class LiteralDouble : public Literal 19 | { 20 | private: 21 | /** 22 | * The actual value 23 | * @var double 24 | */ 25 | const double _value; 26 | 27 | /** 28 | * The provided string representation of the literal 29 | * @var std::string 30 | */ 31 | std::unique_ptr _token; 32 | 33 | public: 34 | /** 35 | * Constructor 36 | * @param token 37 | */ 38 | LiteralDouble(Token *token) 39 | : _value(std::strtod(token->c_str(), nullptr)), _token(token) {} 40 | 41 | /** 42 | * Destructor 43 | */ 44 | virtual ~LiteralDouble() {} 45 | 46 | /** 47 | * The return type of the expression 48 | * @return Type 49 | */ 50 | Type type() const override { return Type::Double; } 51 | 52 | /** 53 | * Generate the code to get the const char * to the expression 54 | * @param generator 55 | */ 56 | virtual void toString(Generator *generator) const override 57 | { 58 | // create string literal 59 | generator->stringValue(*_token); 60 | } 61 | 62 | /** 63 | * Generate the code to get the boolean value of the expression 64 | * @param generator 65 | */ 66 | virtual void toBoolean(Generator *generator) const override 67 | { 68 | // create numeric literal 69 | generator->integerValue(_value ? 1 : 0); 70 | } 71 | 72 | /** 73 | * Generate the code to get the numeric value of the expression 74 | * @param generator 75 | */ 76 | virtual void toInteger(Generator *generator) const override 77 | { 78 | // create numeric literal (We actually don't really want to reach this I think) 79 | generator->integerValue(_value); 80 | } 81 | 82 | /** 83 | * Generate the expression as a double value 84 | * @param generator 85 | */ 86 | virtual void toDouble(Generator *generator) const override 87 | { 88 | // create a double type 89 | generator->doubleValue(_value); 90 | } 91 | 92 | /** 93 | * Generate expression as a pointer to the runtime space 94 | * @param generator 95 | */ 96 | virtual void toPointer(Generator *generator) const override 97 | { 98 | // call the appropriate function in the generator 99 | generator->pointerDouble(this); 100 | } 101 | }; 102 | 103 | /** 104 | * End namespace 105 | */ 106 | }} 107 | -------------------------------------------------------------------------------- /src/expressions/literalinteger.h: -------------------------------------------------------------------------------- 1 | /** 2 | * LiteralInteger.h 3 | * 4 | * Implementation of a literal numeric value 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class LiteralInteger : public Literal 19 | { 20 | private: 21 | /** 22 | * The actual value 23 | * @var integer_t 24 | */ 25 | const integer_t _value; 26 | 27 | /** 28 | * The provided string representation of the literal 29 | * @var std::string 30 | */ 31 | std::unique_ptr _token; 32 | 33 | public: 34 | /** 35 | * Constructor 36 | * @param token 37 | */ 38 | LiteralInteger(Token *token) 39 | : _value(std::strtoll(token->c_str(), nullptr, 10)), _token(token) {} 40 | 41 | /** 42 | * Destructor 43 | */ 44 | virtual ~LiteralInteger() {} 45 | 46 | /** 47 | * The return type of the expression 48 | * @return Type 49 | */ 50 | Type type() const override { return Type::Integer; } 51 | 52 | /** 53 | * Generate the code to get the const char * to the expression 54 | * @param generator 55 | */ 56 | virtual void toString(Generator *generator) const override 57 | { 58 | // create string literal 59 | generator->stringValue(*_token); 60 | } 61 | 62 | /** 63 | * Generate the code to get the boolean value of the expression 64 | * @param generator 65 | */ 66 | virtual void toBoolean(Generator *generator) const override 67 | { 68 | // create numeric literal 69 | generator->integerValue(_value ? 1 : 0); 70 | } 71 | 72 | /** 73 | * Generate the code to get the numeric value of the expression 74 | * @param generator 75 | */ 76 | virtual void toInteger(Generator *generator) const override 77 | { 78 | // create numeric literal 79 | generator->integerValue(_value); 80 | } 81 | 82 | /** 83 | * Generate the expression as a double value 84 | * @param generator 85 | */ 86 | virtual void toDouble(Generator *generator) const override 87 | { 88 | // turn out numeric value into a double 89 | generator->doubleValue(_value); 90 | } 91 | 92 | /** 93 | * Generate expression as a pointer to the runtime space 94 | * @param generator 95 | */ 96 | virtual void toPointer(Generator *generator) const override 97 | { 98 | // call the appropriate function in the generator 99 | generator->pointerInteger(this); 100 | } 101 | }; 102 | 103 | /** 104 | * End namespace 105 | */ 106 | }} 107 | -------------------------------------------------------------------------------- /src/expressions/literalstring.h: -------------------------------------------------------------------------------- 1 | /** 2 | * String.h 3 | * 4 | * Implementation of a literal string value 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class LiteralString : public Literal 19 | { 20 | private: 21 | /** 22 | * The actual value 23 | * @var std::string 24 | */ 25 | std::unique_ptr _value; 26 | 27 | public: 28 | /** 29 | * Constructor 30 | * @param std::string 31 | */ 32 | LiteralString(Token *value) : _value(value) {} 33 | 34 | /** 35 | * Destructor 36 | */ 37 | virtual ~LiteralString() {} 38 | 39 | /** 40 | * The return type of the expression 41 | * @return Type 42 | */ 43 | Type type() const override { return Type::String; } 44 | 45 | /** 46 | * Generate the code to get the const char * to the expression 47 | * @param generator 48 | */ 49 | virtual void toString(Generator *generator) const override 50 | { 51 | // generate our actual value 52 | generator->stringValue(*_value); 53 | } 54 | 55 | /** 56 | * Generate the code to get the boolean value of the expression 57 | * @param generator 58 | */ 59 | virtual void toBoolean(Generator *generator) const override 60 | { 61 | // call the numeric generator with wether we're empty or not 62 | generator->integerValue(!_value->empty()); 63 | } 64 | 65 | /** 66 | * Generate the code to get the integer value of the expression 67 | * @param generator 68 | */ 69 | virtual void toInteger(Generator *generator) const override 70 | { 71 | try 72 | { 73 | // try to parse the string 74 | generator->integerValue(std::strtoll(_value->c_str(), nullptr, 10)); 75 | } 76 | catch (...) 77 | { 78 | // if that doesn't work just return 0 79 | generator->integerValue(0); 80 | } 81 | } 82 | 83 | /** 84 | * Generate the expression as a double value 85 | * @param generator 86 | */ 87 | virtual void toDouble(Generator *generator) const override 88 | { 89 | try 90 | { 91 | // try to parse the string 92 | generator->doubleValue(std::strtod(_value->c_str(), nullptr)); 93 | } 94 | catch (...) 95 | { 96 | // if that doesn't work just return 0 97 | generator->doubleValue(0); 98 | } 99 | } 100 | 101 | /** 102 | * Generate expression as a pointer to the runtime space 103 | * @param generator 104 | */ 105 | virtual void toPointer(Generator *generator) const override 106 | { 107 | // call the appropriate function in the generator 108 | generator->pointerString(this); 109 | } 110 | }; 111 | 112 | /** 113 | * End namespace 114 | */ 115 | }} 116 | -------------------------------------------------------------------------------- /src/expressions/literalvariable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * LiteralVariable.h 3 | * 4 | * Expression that contains one variable. 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class LiteralVariable : public Variable 19 | { 20 | private: 21 | /** 22 | * Name of the variable 23 | * @var std::unique_ptr 24 | */ 25 | std::unique_ptr _name; 26 | 27 | public: 28 | /** 29 | * Constructor 30 | * @param token 31 | */ 32 | LiteralVariable(Token *token) : 33 | _name(token) {} 34 | 35 | /** 36 | * Destructor 37 | */ 38 | virtual ~LiteralVariable() {} 39 | 40 | /** 41 | * The return type of the expression 42 | * @return Type 43 | */ 44 | Type type() const override { return Type::Value; } 45 | 46 | /** 47 | * Generate the output that leaves a pointer to the variable 48 | * @param generator 49 | */ 50 | void pointer(Generator *generator) const override 51 | { 52 | // generate the code to get a variable pointer 53 | generator->varPointer(*_name); 54 | } 55 | 56 | }; 57 | 58 | /** 59 | * End of namespace 60 | */ 61 | }} -------------------------------------------------------------------------------- /src/expressions/variable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Variable.h 3 | * 4 | * Expression that contains one variable. 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Variable : public Expression 19 | { 20 | protected: 21 | /** 22 | * Constructor 23 | */ 24 | Variable() {} 25 | 26 | public: 27 | /** 28 | * Destructor 29 | */ 30 | virtual ~Variable() = default; 31 | 32 | /** 33 | * Generate the output that leaves a pointer to the variable 34 | * @param generator 35 | */ 36 | virtual void pointer(Generator *generator) const = 0; 37 | 38 | /** 39 | * Generate a numeric code for the variable 40 | * @param generator 41 | */ 42 | virtual void toInteger(Generator *generator) const override 43 | { 44 | generator->integerVariable(this); 45 | } 46 | 47 | /** 48 | * Generate the expression as a double value 49 | * @param generator 50 | */ 51 | virtual void toDouble(Generator *generator) const override 52 | { 53 | // turn out numeric value into a double 54 | generator->doubleVariable(this); 55 | } 56 | 57 | /** 58 | * Generate a boolean code for the variable 59 | * @param generator 60 | */ 61 | virtual void toBoolean(Generator *generator) const override 62 | { 63 | generator->booleanVariable(this); 64 | } 65 | 66 | /** 67 | * Generate a string for the variable 68 | * @param generator 69 | */ 70 | virtual void toString(Generator *generator) const override 71 | { 72 | generator->stringVariable(this); 73 | } 74 | 75 | /** 76 | * Generate a pointer for this variable 77 | * @param generator 78 | */ 79 | virtual void toPointer(Generator *generator) const override 80 | { 81 | // equal to the other pointer method 82 | this->pointer(generator); 83 | } 84 | 85 | /** 86 | * Generate the expression to output ourself 87 | * @param generator 88 | */ 89 | virtual void output(Generator *generator) const override 90 | { 91 | generator->output(this); 92 | } 93 | }; 94 | 95 | /** 96 | * End of namespace 97 | */ 98 | }} 99 | -------------------------------------------------------------------------------- /src/expressions/variablearrayaccess.h: -------------------------------------------------------------------------------- 1 | /** 2 | * VariableArrayAccess.h 3 | * 4 | * Class that is used to represent the [] operator to get access to an array 5 | * member, when used with a variable string (an expression) 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * Class definition 18 | */ 19 | class VariableArrayAccess : public ArrayAccess 20 | { 21 | protected: 22 | /** 23 | * The key that is accessed 24 | * @var Expression 25 | */ 26 | std::unique_ptr _key; 27 | 28 | public: 29 | /** 30 | * Constructor 31 | * @param variable 32 | * @param key 33 | */ 34 | VariableArrayAccess(Variable *variable, Expression *key) : 35 | ArrayAccess(variable), 36 | _key(key) {} 37 | 38 | /** 39 | * Destructor 40 | */ 41 | virtual ~VariableArrayAccess() {} 42 | 43 | /** 44 | * The return type of the expression 45 | * @return Type 46 | */ 47 | Type type() const override { return Type::Value; } 48 | 49 | /** 50 | * Generate a call that creates a pointer to a variable 51 | * @param generator 52 | */ 53 | void pointer(Generator *generator) const override 54 | { 55 | generator->varPointer(_var.get(), _key.get()); 56 | } 57 | }; 58 | 59 | /** 60 | * End namespace 61 | */ 62 | }} -------------------------------------------------------------------------------- /src/iterator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Iterator.h 3 | * 4 | * Class that internally keeps track of the status of a foreach loop 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Include guard 12 | */ 13 | #pragma once 14 | 15 | /** 16 | * Set up namespace 17 | */ 18 | namespace SmartTpl { namespace Internal { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class Iterator 24 | { 25 | private: 26 | /** 27 | * Iterator 28 | * 29 | * @var SmartTpl::Iterator 30 | */ 31 | std::unique_ptr _iterator; 32 | 33 | public: 34 | /** 35 | * Constructor 36 | * @param source The source value object to iterate over 37 | */ 38 | Iterator(const Value *source) : 39 | _iterator(source->iterator()) {} 40 | 41 | /** 42 | * Destructor 43 | */ 44 | virtual ~Iterator() 45 | { 46 | // @todo remove the key and value from the local variables?? 47 | // 48 | // (although i do not think it is disastrous if we keep 49 | // the loop-variables in scope after the loop if completed) 50 | } 51 | 52 | /** 53 | * Check if the iterator is still valid 54 | * @return bool 55 | */ 56 | bool valid() const 57 | { 58 | // if we have a valid _iterator call the valid() method on it 59 | if (_iterator) return _iterator->valid(); 60 | 61 | // Otherwise we'll be invalid 62 | return false; 63 | } 64 | 65 | /** 66 | * Retrieve a pointer to the current key 67 | * @return Variant 68 | */ 69 | VariantValue key() const 70 | { 71 | return _iterator->key(); 72 | } 73 | 74 | /** 75 | * Retrieve pointer to the current member 76 | * @return Variant 77 | */ 78 | VariantValue value() const 79 | { 80 | return _iterator->value(); 81 | } 82 | 83 | /** 84 | * Move to the next position 85 | */ 86 | void next() 87 | { 88 | // increment position 89 | _iterator->next(); 90 | } 91 | }; 92 | 93 | /** 94 | * End of namespace 95 | */ 96 | }} -------------------------------------------------------------------------------- /src/jit_exception.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Jit_Exception.h 3 | * 4 | * A custom exception which will turn a libjit exception code into a human 5 | * readable error 6 | * 7 | * @author Toon Schoenmakers 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * Class definition 18 | */ 19 | class JitException : public std::runtime_error 20 | { 21 | private: 22 | std::string initialize(int exception_type) 23 | { 24 | // convert the exception type to a human readable string 25 | // source: https://github.com/agalakhov/libjit/blob/master/jit/jit-except.c#L213 26 | switch (exception_type) { 27 | case JIT_RESULT_OVERFLOW: 28 | return "Overflow during checked arithmetic operation"; 29 | case JIT_RESULT_ARITHMETIC: 30 | return "Arithmetic exception (dividing the minimum integer by -1)"; 31 | case JIT_RESULT_DIVISION_BY_ZERO: 32 | return "Division by zero"; 33 | case JIT_RESULT_COMPILE_ERROR: 34 | return "Error during function compilation"; 35 | case JIT_RESULT_OUT_OF_MEMORY: 36 | return "Out of memory"; 37 | case JIT_RESULT_NULL_REFERENCE: 38 | return "Null pointer dereferenced"; 39 | case JIT_RESULT_NULL_FUNCTION: 40 | return "Null function pointer called"; 41 | case JIT_RESULT_CALLED_NESTED: 42 | return "Nested function called from non-nested context"; 43 | case JIT_RESULT_OUT_OF_BOUNDS: 44 | return "Array index out of bounds"; 45 | case JIT_RESULT_UNDEFINED_LABEL: 46 | return "Undefined label"; 47 | case JIT_RESULT_OK: // I'm assuming this will never actually happen.. 48 | return "Uhm, success?"; 49 | default: 50 | return "Unknown exception " + std::to_string(exception_type); 51 | }; 52 | } 53 | 54 | public: 55 | /** 56 | * Constructor 57 | */ 58 | JitException(int exception_type) 59 | : std::runtime_error(initialize(exception_type)) 60 | { 61 | } 62 | 63 | /** 64 | * Deconstructor 65 | */ 66 | virtual ~JitException() {}; 67 | 68 | /** 69 | * Custom exception handler for libjit 70 | * We purely need this as the default exception handler of libjit will call 71 | * exit(1); Which we obviously don't want. The only way around this is to 72 | * register our own exception handler and throw a C++ exception from there 73 | * so it'll jump over parts of the default libjit exception handler. 74 | */ 75 | static void* handler(int exception_type) 76 | { 77 | throw JitException(exception_type); 78 | } 79 | }; 80 | 81 | /** 82 | * End namespace 83 | */ 84 | }} -------------------------------------------------------------------------------- /src/library.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Library.cpp 3 | * 4 | * Implementation file for the Library class 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | #include "includes.h" 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * Structure with all the callbacks 18 | * @var smart_tpl_callbacks 19 | */ 20 | static struct smart_tpl_callbacks callbacks = { 21 | .write = smart_tpl_write, 22 | .output = smart_tpl_output, 23 | .output_integer = smart_tpl_output_integer, 24 | .output_boolean = smart_tpl_output_boolean, 25 | .output_double = smart_tpl_output_double, 26 | .member = smart_tpl_member, 27 | .member_at = smart_tpl_member_at, 28 | .member_at_value = smart_tpl_member_at_value, 29 | .transfer_integer = smart_tpl_transfer_integer, 30 | .transfer_double = smart_tpl_transfer_double, 31 | .transfer_string = smart_tpl_transfer_string, 32 | .transfer_boolean = smart_tpl_transfer_boolean, 33 | .plus = smart_tpl_plus, 34 | .minus = smart_tpl_minus, 35 | .multiply = smart_tpl_multiply, 36 | .divide = smart_tpl_divide, 37 | .modulo = smart_tpl_modulo, 38 | .create_iterator = smart_tpl_create_iterator, 39 | .valid_iterator = smart_tpl_valid_iterator, 40 | .iterator_key = smart_tpl_iterator_key, 41 | .iterator_value = smart_tpl_iterator_value, 42 | .iterator_next = smart_tpl_iterator_next, 43 | .variable = smart_tpl_variable, 44 | .to_string = smart_tpl_to_string, 45 | .to_integer = smart_tpl_to_integer, 46 | .to_double = smart_tpl_to_double, 47 | .to_boolean = smart_tpl_to_boolean, 48 | .size = smart_tpl_size, 49 | .modifier = smart_tpl_modifier, 50 | .modify_variable = smart_tpl_modify_variable, 51 | .assign_integer = smart_tpl_assign_integer, 52 | .assign_double = smart_tpl_assign_double, 53 | .assign_boolean = smart_tpl_assign_boolean, 54 | .assign_string = smart_tpl_assign_string, 55 | .assign = smart_tpl_assign, 56 | .strcmp = smart_tpl_strcmp, 57 | .create_params = smart_tpl_create_params, 58 | .params_append_integer = smart_tpl_params_append_integer, 59 | .params_append_double = smart_tpl_params_append_double, 60 | .params_append_string = smart_tpl_params_append_string, 61 | .params_append_boolean = smart_tpl_params_append_boolean, 62 | .mark_failed = smart_tpl_mark_failed, 63 | .throw_exception = smart_tpl_throw_exception, 64 | }; 65 | 66 | /** 67 | * Execute the template given a certain data source 68 | * @param data 69 | */ 70 | void Library::process(Handler &handler) 71 | { 72 | // call the function 73 | _function(&callbacks, &handler); 74 | } 75 | 76 | /** 77 | * End namespace 78 | */ 79 | }} 80 | -------------------------------------------------------------------------------- /src/map_iterator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Map_Iterator.h 3 | * 4 | * Iterator for MapValues 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class MapIterator : public SmartTpl::Iterator 19 | { 20 | private: 21 | /** 22 | * The map we're iterating over 23 | */ 24 | const std::map _map; 25 | 26 | /** 27 | * Iterator to the current position in our map 28 | */ 29 | std::map::const_iterator _iter; 30 | 31 | /** 32 | * End iterator which indicates where we should stop 33 | */ 34 | const std::map::const_iterator _end; 35 | 36 | public: 37 | /** 38 | * Constructor 39 | */ 40 | MapIterator(const std::map &value) 41 | : _map(value), 42 | _iter(_map.begin()), 43 | _end(_map.end()) 44 | {} 45 | 46 | /** 47 | * Deconstructor 48 | */ 49 | virtual ~MapIterator() {} 50 | 51 | /** 52 | * Check if the iterator is still valid 53 | * @return bool 54 | */ 55 | bool valid() const override 56 | { 57 | return _iter != _end; 58 | } 59 | 60 | /** 61 | * Move to the next position 62 | */ 63 | void next() override 64 | { 65 | ++_iter; 66 | } 67 | 68 | /** 69 | * Retrieve pointer to the current member 70 | * @return Variant 71 | */ 72 | VariantValue value() const override 73 | { 74 | return _iter->second; 75 | } 76 | 77 | /** 78 | * Retrieve a pointer to the current key 79 | * @return Variant 80 | */ 81 | VariantValue key() const override 82 | { 83 | return _iter->first; 84 | } 85 | }; 86 | 87 | /** 88 | * End namespace 89 | */ 90 | }} -------------------------------------------------------------------------------- /src/mapvalue.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * MapValue.cpp 3 | * 4 | * A SmartTpl::Value which represents a map with VariantValues 5 | * this is only a cpp file because the map iterator is an internal class 6 | * 7 | * @author Toon Schoenmakers 8 | * @copyright 2014 Copernica BV 9 | */ 10 | #include "includes.h" 11 | 12 | /** 13 | * Set up namespace 14 | */ 15 | namespace SmartTpl { 16 | 17 | Iterator *MapValue::iterator() const 18 | { 19 | return new Internal::MapIterator(_value); 20 | } 21 | 22 | /** 23 | * End namespace 24 | */ 25 | } -------------------------------------------------------------------------------- /src/modifiers/modifierexpression.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ModifierExpression.h 3 | * 4 | * A single modifier that is applied to an expression ("$a|modifier") 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class ModifierExpression 19 | { 20 | private: 21 | /** 22 | * Name of the variable 23 | * @var Token 24 | */ 25 | std::unique_ptr _name; 26 | 27 | /** 28 | * Optional additional parameters 29 | * @var Parameters 30 | */ 31 | std::unique_ptr _parameters; 32 | 33 | public: 34 | /** 35 | * Constructor 36 | * @param name 37 | */ 38 | ModifierExpression(const Token *name) : _name(name) {} 39 | 40 | /** 41 | * Constructor 42 | * @param name 43 | * @param parameters 44 | */ 45 | ModifierExpression(const Token *name, const Parameters *parameters) : _name(name), _parameters(parameters) {} 46 | 47 | /** 48 | * Destructor 49 | */ 50 | virtual ~ModifierExpression() {} 51 | 52 | /** 53 | * The name of the modifier 54 | * @return const std::string 55 | */ 56 | const std::string &token() const { return *_name; }; 57 | 58 | /** 59 | * Returns the internal Parameters object 60 | */ 61 | const Parameters *parameters() const { return _parameters.get(); }; 62 | 63 | }; 64 | 65 | /** 66 | * End namespace 67 | */ 68 | }} 69 | -------------------------------------------------------------------------------- /src/modifiers/modifiers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Modifiers.h 3 | * 4 | * List of modifiers that make up a filter 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2018 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Modifiers 19 | { 20 | public: 21 | /** 22 | * const_iterator typedef 23 | */ 24 | typedef std::list>::const_iterator const_iterator; 25 | typedef std::list>::const_reverse_iterator const_reverse_iterator; 26 | private: 27 | /** 28 | * List of modifiers 29 | * @var std::list 30 | */ 31 | std::list> _modifiers; 32 | 33 | public: 34 | /** 35 | * Constructor 36 | * @param modifier 37 | */ 38 | Modifiers(const ModifierExpression *modifier) 39 | { 40 | add(modifier); 41 | } 42 | 43 | /** 44 | * Destructor 45 | */ 46 | virtual ~Modifiers() {} 47 | 48 | /** 49 | * Add a modifier to the list of modifiers 50 | * @param modifier 51 | */ 52 | void add(const ModifierExpression *modifier) 53 | { 54 | _modifiers.emplace_back(modifier); 55 | } 56 | 57 | /** 58 | * Generate the output of these modifiers 59 | * @param generator 60 | * @param variable 61 | * @note pointer to a variable is added to the stack 62 | */ 63 | void generate(Generator *generator, const Variable *variable) const 64 | { 65 | generator->modifiers(this, variable); 66 | } 67 | 68 | /** 69 | * Generate the code for modifiers but turning it into a string 70 | * @param generator 71 | * @param variable 72 | */ 73 | void generateString(Generator *generator, const Variable *variable) const 74 | { 75 | generator->modifiersString(this, variable); 76 | } 77 | 78 | /** 79 | * Generate the code for modifiers but turning it into a boolean, this 80 | * is mostly used for if statements 81 | * @param generator 82 | * @param variable 83 | */ 84 | void generateBoolean(Generator *generator, const Variable *variable) const 85 | { 86 | generator->modifiersBoolean(this, variable); 87 | } 88 | 89 | /** 90 | * Generate the code for modifiers but turning it into a double, this is mostly 91 | * used for if statements 92 | * @param generator 93 | * @param variable 94 | */ 95 | void generateDouble(Generator *generator, const Variable *variable) const 96 | { 97 | generator->modifiersDouble(this, variable); 98 | } 99 | 100 | /** 101 | * Get the begin and end iterator 102 | */ 103 | const_iterator begin() const { return _modifiers.begin(); } 104 | const_iterator end() const { return _modifiers.end(); } 105 | const_reverse_iterator rbegin() const { return _modifiers.rbegin(); } 106 | const_reverse_iterator rend() const { return _modifiers.rend(); } 107 | 108 | /** 109 | * A simple size() method 110 | */ 111 | std::size_t size() const { return _modifiers.size(); } 112 | }; 113 | 114 | /** 115 | * End namespace 116 | */ 117 | }} 118 | -------------------------------------------------------------------------------- /src/modifiers/parameters.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Parameters.h 3 | * 4 | * Parameters that are passed to a modifier function. 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Parameters 19 | { 20 | public: 21 | /** 22 | * const_iterator typedef 23 | */ 24 | typedef std::list>::const_iterator const_iterator; 25 | typedef std::list>::const_reverse_iterator const_reverse_iterator; 26 | private: 27 | /** 28 | * List of parameters 29 | * @var std::list 30 | */ 31 | std::list> _parameters; 32 | 33 | public: 34 | /** 35 | * Constructor 36 | * @param expression 37 | */ 38 | Parameters(const Expression *expression) 39 | { 40 | add(expression); 41 | } 42 | 43 | /** 44 | * Destructor 45 | */ 46 | virtual ~Parameters() {} 47 | 48 | /** 49 | * Add a parameter 50 | * @param expression 51 | */ 52 | void add(const Expression *expression) 53 | { 54 | _parameters.emplace_back(expression); 55 | } 56 | 57 | /** 58 | * Generate the output to construct these parameters on runtime 59 | * @param generator 60 | */ 61 | void generate(Generator *generator) const 62 | { 63 | generator->parameters(this); 64 | } 65 | 66 | /** 67 | * Get the begin and end iterator 68 | */ 69 | const_iterator begin() const { return _parameters.begin(); } 70 | const_iterator end() const { return _parameters.end(); } 71 | const_reverse_iterator rbegin() const { return _parameters.rbegin(); } 72 | const_reverse_iterator rend() const { return _parameters.rend(); } 73 | 74 | /** 75 | * Get the amount of parameters 76 | */ 77 | size_t size() const { return _parameters.size(); } 78 | }; 79 | 80 | /** 81 | * End namespace 82 | */ 83 | }} -------------------------------------------------------------------------------- /src/operators/binary.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Binary.h 3 | * 4 | * Base class for binary operators. 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryOperator : public Operator 19 | { 20 | protected: 21 | /** 22 | * Left side of the operator 23 | * @var Expression 24 | */ 25 | std::unique_ptr _left; 26 | 27 | /** 28 | * Right side of the operator 29 | * @var Expression 30 | */ 31 | std::unique_ptr _right; 32 | 33 | 34 | public: 35 | /** 36 | * Protected constructor because this is just a base class 37 | * @param left 38 | * @param right 39 | */ 40 | BinaryOperator(Expression *left, Expression *right) : 41 | _left(left), 42 | _right(right) {} 43 | 44 | /** 45 | * Destructor 46 | */ 47 | virtual ~BinaryOperator() {} 48 | 49 | /** 50 | * The return type of the expression 51 | * @return Type 52 | */ 53 | virtual Type type() const override { return Type::Boolean; } 54 | }; 55 | 56 | /** 57 | * End namespace 58 | */ 59 | }} -------------------------------------------------------------------------------- /src/operators/binaryand.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryAnd.h 3 | * 4 | * Implementation of the binary && operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryAndOperator : public BinaryBooleanOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryAndOperator(Expression *left, Expression *right) : 27 | BinaryBooleanOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryAndOperator() {} 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->booleanAnd(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->booleanAnd(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/binaryarithmetric.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryArtithmetric.h 3 | * 4 | * Class for arithmetric operators 5 | * 6 | * @copyright 2014 - 2019 Copernica BV 7 | */ 8 | 9 | /** 10 | * Set up namespace 11 | */ 12 | namespace SmartTpl { namespace Internal { 13 | 14 | /** 15 | * Class definition 16 | */ 17 | class BinaryArithmetricOperator : public BinaryOperator 18 | { 19 | public: 20 | /** 21 | * Constructor 22 | * @param left 23 | * @param right 24 | */ 25 | BinaryArithmetricOperator(Expression *left, Expression *right) : 26 | BinaryOperator(left, right) {} 27 | 28 | /** 29 | * Destructor 30 | */ 31 | virtual ~BinaryArithmetricOperator() {} 32 | 33 | /** 34 | * The return type of the expression 35 | * @return Type 36 | */ 37 | virtual Type type() const override 38 | { 39 | // if both types are integer, so is the result of the operation 40 | if (_left->type() == Type::Integer && _right->type() == Type::Integer) return Type::Integer; 41 | 42 | // if one of the types is double, so is the entire operation 43 | if (_left->type() == Type::Double || _right->type() == Type::Double) return Type::Double; 44 | 45 | // otherwise, we have to determine at runtime 46 | return Type::Value; 47 | } 48 | }; 49 | 50 | /** 51 | * End namespace 52 | */ 53 | }} 54 | -------------------------------------------------------------------------------- /src/operators/binaryboolean.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryBoolean.h 3 | * 4 | * Base class for boolean operators 5 | * 6 | * @copyright 2014 - 2019 Copernica BV 7 | */ 8 | 9 | /** 10 | * Set up namespace 11 | */ 12 | namespace SmartTpl { namespace Internal { 13 | 14 | /** 15 | * Class definition 16 | */ 17 | class BinaryBooleanOperator : public BinaryOperator 18 | { 19 | public: 20 | /** 21 | * Constructor 22 | * @param left 23 | * @param right 24 | */ 25 | BinaryBooleanOperator(Expression *left, Expression *right) : 26 | BinaryOperator(left, right) {} 27 | 28 | /** 29 | * Destructor 30 | */ 31 | virtual ~BinaryBooleanOperator() {} 32 | 33 | /** 34 | * Generate the code to get the const char * to the expression 35 | * @param generator 36 | */ 37 | virtual void toString(Generator *generator) const override 38 | { 39 | // this is wrong, because we can send "true" or "false" to the output, but 40 | // inside ByteCode.cpp and CCode.cpp we have a special case for boolean output 41 | generator->stringValue(""); 42 | } 43 | }; 44 | 45 | /** 46 | * End namespace 47 | */ 48 | }} 49 | -------------------------------------------------------------------------------- /src/operators/binarycompare.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryCompare.h 3 | * 4 | * Base class for comparison operators 5 | * 6 | * @copyright 2014 Copernica BV 7 | */ 8 | 9 | /** 10 | * Set up namespace 11 | */ 12 | namespace SmartTpl { namespace Internal { 13 | 14 | /** 15 | * Class definition 16 | */ 17 | class BinaryCompareOperator : public BinaryOperator 18 | { 19 | public: 20 | /** 21 | * Constructor 22 | * @param left 23 | * @param right 24 | */ 25 | BinaryCompareOperator(Expression *left, Expression *right) : 26 | BinaryOperator(left, right) {} 27 | 28 | /** 29 | * Destructor 30 | */ 31 | virtual ~BinaryCompareOperator() {} 32 | }; 33 | 34 | /** 35 | * End namespace 36 | */ 37 | }} -------------------------------------------------------------------------------- /src/operators/binarydivide.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryDivide.h 3 | * 4 | * Implementation of the binary divide operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryDivideOperator : public BinaryArithmetricOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryDivideOperator(Expression *left, Expression *right) : 27 | BinaryArithmetricOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryDivideOperator() {} 33 | 34 | /** 35 | * Generate the operator to a numeric value 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->integerDivide(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the operator to a double value 45 | * @param generator 46 | */ 47 | virtual void toDouble(Generator *generator) const override 48 | { 49 | generator->doubleDivide(_left.get(), _right.get()); 50 | } 51 | 52 | /** 53 | * Generate the operator to a pointer value 54 | * @param generator 55 | */ 56 | virtual void toPointer(Generator *generator) const override 57 | { 58 | generator->pointerDivide(_left.get(), _right.get()); 59 | } 60 | }; 61 | 62 | /** 63 | * End of namespace 64 | */ 65 | }} 66 | -------------------------------------------------------------------------------- /src/operators/binaryequals.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryEquals.h 3 | * 4 | * Implementation of the binary equals operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryEqualsOperator : public BinaryCompareOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryEqualsOperator(Expression *left, Expression *right) : 27 | BinaryCompareOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryEqualsOperator() {} 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->equals(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->equals(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/binarygreater.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryGreater.h 3 | * 4 | * Implementation of the binary greater operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryGreaterOperator : public BinaryCompareOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryGreaterOperator(Expression *left, Expression *right) : 27 | BinaryCompareOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryGreaterOperator() {} 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->greater(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->greater(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/binarygreaterequals.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryGreaterEquals.h 3 | * 4 | * Implementation of the binary greater-or-equals operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryGreaterEqualsOperator : public BinaryCompareOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryGreaterEqualsOperator(Expression *left, Expression *right) : 27 | BinaryCompareOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryGreaterEqualsOperator() {} 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->greaterEquals(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->greaterEquals(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/binarylesser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryLesser.h 3 | * 4 | * Implementation of the binary lesser operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryLesserOperator : public BinaryCompareOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryLesserOperator(Expression *left, Expression *right) : 27 | BinaryCompareOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryLesserOperator() {} 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->lesser(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->lesser(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/binarylesserequals.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryLesserEquals.h 3 | * 4 | * Implementation of the binary lesser-or-equals operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryLesserEqualsOperator : public BinaryCompareOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryLesserEqualsOperator(Expression *left, Expression *right) : 27 | BinaryCompareOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryLesserEqualsOperator() {} 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->lesserEquals(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->lesserEquals(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/binaryminus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryMinus.h 3 | * 4 | * Implementation of the binary minus operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryMinusOperator : public BinaryArithmetricOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryMinusOperator(Expression *left, Expression *right) : 27 | BinaryArithmetricOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryMinusOperator() {} 33 | 34 | /** 35 | * Generate the operator to a numeric value 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->integerMinus(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the operator to a double value 45 | * @param generator 46 | */ 47 | virtual void toDouble(Generator *generator) const override 48 | { 49 | generator->doubleMinus(_left.get(), _right.get()); 50 | } 51 | 52 | /** 53 | * Generate the operator to a pointer value 54 | * @param generator 55 | */ 56 | virtual void toPointer(Generator *generator) const override 57 | { 58 | generator->pointerMinus(_left.get(), _right.get()); 59 | } 60 | }; 61 | 62 | /** 63 | * End of namespace 64 | */ 65 | }} 66 | -------------------------------------------------------------------------------- /src/operators/binarymodulo.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryModuloOperator.h 3 | * 4 | * Implementation of the binary modulo operator 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryModuloOperator : public BinaryArithmetricOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryModuloOperator(Expression *left, Expression *right) : 27 | BinaryArithmetricOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryModuloOperator() {} 33 | 34 | /** 35 | * Generate the operator to a numeric value 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->integerModulo(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the operator to a double value 45 | * @param generator 46 | */ 47 | virtual void toDouble(Generator *generator) const override 48 | { 49 | generator->integerModulo(_left.get(), _right.get()); 50 | } 51 | 52 | /** 53 | * Generate the operator to a pointer value 54 | * @param generator 55 | */ 56 | virtual void toPointer(Generator *generator) const override 57 | { 58 | generator->pointerModulo(_left.get(), _right.get()); 59 | } 60 | 61 | /** 62 | * The return type of the expression 63 | * @return Type 64 | */ 65 | virtual Type type() const override 66 | { 67 | // Modulo operations are always integer 68 | return Type::Integer; 69 | } 70 | 71 | }; 72 | 73 | /** 74 | * End of namespace 75 | */ 76 | }} 77 | -------------------------------------------------------------------------------- /src/operators/binarymultiply.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryMultiply.h 3 | * 4 | * Implementation of the binary multiply operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryMultiplyOperator : public BinaryArithmetricOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryMultiplyOperator(Expression *left, Expression *right) : 27 | BinaryArithmetricOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryMultiplyOperator() {} 33 | 34 | /** 35 | * Generate the operator to a numeric value 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->integerMultiply(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the operator to a double value 45 | * @param generator 46 | */ 47 | virtual void toDouble(Generator *generator) const override 48 | { 49 | generator->doubleMultiply(_left.get(), _right.get()); 50 | } 51 | 52 | /** 53 | * Generate the operator to a pointer value 54 | * @param generator 55 | */ 56 | virtual void toPointer(Generator *generator) const override 57 | { 58 | generator->pointerMultiply(_left.get(), _right.get()); 59 | } 60 | }; 61 | 62 | /** 63 | * End of namespace 64 | */ 65 | }} 66 | -------------------------------------------------------------------------------- /src/operators/binarynotequals.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryNotEquals.h 3 | * 4 | * Implementation of the binary not-equals operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryNotEqualsOperator : public BinaryCompareOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryNotEqualsOperator(Expression *left, Expression *right) : 27 | BinaryCompareOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryNotEqualsOperator() {} 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->notEquals(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->notEquals(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/binaryor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryOr.h 3 | * 4 | * Implementation of the binary || operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryOrOperator : public BinaryBooleanOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryOrOperator(Expression *left, Expression *right) : 27 | BinaryBooleanOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryOrOperator() {} 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->booleanOr(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->booleanOr(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/binaryplus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryPlus.h 3 | * 4 | * Implementation of the binary plus operator 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryPlusOperator : public BinaryArithmetricOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryPlusOperator(Expression *left, Expression *right) : 27 | BinaryArithmetricOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryPlusOperator() {} 33 | 34 | /** 35 | * Generate the operator to a numeric value 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->integerPlus(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the operator to a double value 45 | * @param generator 46 | */ 47 | virtual void toDouble(Generator *generator) const override 48 | { 49 | generator->doublePlus(_left.get(), _right.get()); 50 | } 51 | 52 | /** 53 | * Generate the operator to a pointer value 54 | * @param generator 55 | */ 56 | virtual void toPointer(Generator *generator) const override 57 | { 58 | generator->pointerPlus(_left.get(), _right.get()); 59 | } 60 | }; 61 | 62 | /** 63 | * End of namespace 64 | */ 65 | }} 66 | -------------------------------------------------------------------------------- /src/operators/binaryregex.h: -------------------------------------------------------------------------------- 1 | /** 2 | * BinaryRegex.h 3 | * 4 | * Implementation of the binary regex operator ("=~") 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2018 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class BinaryRegexOperator : public BinaryCompareOperator 19 | { 20 | public: 21 | /** 22 | * Constructor 23 | * @param left 24 | * @param right 25 | */ 26 | BinaryRegexOperator(Expression *left, Expression *right) : 27 | BinaryCompareOperator(left, right) {} 28 | 29 | /** 30 | * Destructor 31 | */ 32 | virtual ~BinaryRegexOperator() = default; 33 | 34 | /** 35 | * Generate the instruction 36 | * @param generator 37 | */ 38 | virtual void toInteger(Generator *generator) const override 39 | { 40 | generator->regex(_left.get(), _right.get()); 41 | } 42 | 43 | /** 44 | * Generate the instruction 45 | * @param generator 46 | */ 47 | virtual void toBoolean(Generator *generator) const override 48 | { 49 | generator->regex(_left.get(), _right.get()); 50 | } 51 | }; 52 | 53 | /** 54 | * End of namespace 55 | */ 56 | }} 57 | -------------------------------------------------------------------------------- /src/operators/operator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Operator.h 3 | * 4 | * Base class for all operators 5 | * 6 | * @author Emiel Bruijntnjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Operator : public Expression 19 | { 20 | protected: 21 | /** 22 | * This is a base class, not allowed to construct it directly, 23 | * hence the protected constructor 24 | */ 25 | Operator() {} 26 | 27 | public: 28 | /** 29 | * Destructor 30 | */ 31 | virtual ~Operator() {} 32 | 33 | }; 34 | 35 | /** 36 | * End namespace 37 | */ 38 | }} -------------------------------------------------------------------------------- /src/quotedstring.h: -------------------------------------------------------------------------------- 1 | /** 2 | * QuotedString.h 3 | * 4 | * Class that takes a string and quotes all input from it so that it can 5 | * be picked up by a compiler 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * Class definition 18 | */ 19 | class QuotedString : public std::string 20 | { 21 | public: 22 | /** 23 | * Constructor 24 | * @param input Input string 25 | */ 26 | QuotedString(const std::string &input) 27 | { 28 | // we reserve plenty of space (normally not more that two or three 29 | // extra characters are necessary 30 | reserve(input.size() + 20); 31 | 32 | // loop through the input 33 | for (char c : input) 34 | { 35 | switch (c) { 36 | case '\a': append("\\a"); break; 37 | case '\n': append("\\n"); break; 38 | case '\r': append("\\r"); break; 39 | case '\0': append("\\0"); break; 40 | case '\t': append("\\t"); break; 41 | case '\f': append("\\f"); break; 42 | case '\b': append("\\b"); break; 43 | case '\v': append("\\v"); break; 44 | case '"' : append("\\\""); break; 45 | case '\'': append("\\\'"); break; 46 | case '\\': append("\\\\"); break; 47 | default: push_back(c); break; 48 | } 49 | } 50 | } 51 | }; 52 | 53 | /** 54 | * End namespace 55 | */ 56 | }} -------------------------------------------------------------------------------- /src/signature_callback.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SignatureCallback.h 3 | * 4 | * Class to easily get the required libjit signatures 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class SignatureCallback 19 | { 20 | protected: 21 | /** 22 | * The signature 23 | * @var jit_type_t 24 | */ 25 | jit_type_t _signature; 26 | 27 | public: 28 | /** 29 | * Constructor 30 | */ 31 | SignatureCallback(std::vector params, jit_type_t return_type = jit_type_void) 32 | : _signature(jit_type_create_signature(jit_abi_cdecl, return_type, params.data(), params.size(), 1)) {} 33 | 34 | /** 35 | * Destructor 36 | */ 37 | ~SignatureCallback() 38 | { 39 | if (_signature) jit_type_free(_signature); 40 | } 41 | 42 | /** 43 | * Retrieve the signature 44 | * @return signature 45 | */ 46 | const jit_type_t &signature() const 47 | { 48 | return _signature; 49 | } 50 | }; 51 | 52 | /** 53 | * End namespace 54 | */ 55 | }} -------------------------------------------------------------------------------- /src/statements/assign.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Assign.h 3 | * 4 | * Statement to assign the output of an expression to a variable 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class AssignStatement : public Statement 19 | { 20 | private: 21 | /** 22 | * The variable we'll assign to 23 | */ 24 | std::unique_ptr _var; 25 | 26 | /** 27 | * The expression we would like to assign 28 | */ 29 | std::unique_ptr _expression; 30 | 31 | public: 32 | /** 33 | * Constructor 34 | * @param expression The expression we would like to assign to a variable 35 | * @param var The variable we would like to assign it to 36 | * @throws std::runtime_error In case the variable is not of type LiteralVariable 37 | */ 38 | AssignStatement(Expression *expression, Token *var) 39 | : _var(var) 40 | , _expression(expression) {} 41 | 42 | /** 43 | * Destructor 44 | */ 45 | virtual ~AssignStatement() {} 46 | 47 | /** 48 | * Generate the output of this statement 49 | * @param generator 50 | */ 51 | void generate(Generator *generator) const override 52 | { 53 | generator->assign(*_var, _expression.get()); 54 | } 55 | }; 56 | 57 | /** 58 | * End of namespace 59 | */ 60 | }} -------------------------------------------------------------------------------- /src/statements/expression.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Expression.h 3 | * 4 | * Statement to echo the output of an expression 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class ExpressionStatement : public Statement 19 | { 20 | private: 21 | /** 22 | * The expression that should be executed 23 | * @var Expression 24 | */ 25 | std::unique_ptr _expression; 26 | 27 | public: 28 | /** 29 | * Constructor 30 | * @param expression 31 | */ 32 | ExpressionStatement(Expression *expression) : _expression(expression) {} 33 | 34 | /** 35 | * Destructor 36 | */ 37 | virtual ~ExpressionStatement() {} 38 | 39 | /** 40 | * Generate the output of this statement 41 | * @param generator 42 | */ 43 | void generate(Generator *generator) const override 44 | { 45 | _expression->output(generator); 46 | } 47 | }; 48 | 49 | /** 50 | * End of namespace 51 | */ 52 | }} -------------------------------------------------------------------------------- /src/statements/foreach.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ForEach.h 3 | * 4 | * Statement to simply loop through all the members of a multi member variable 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class ForEachStatement : public Statement 19 | { 20 | private: 21 | /** 22 | * The variable to loop over 23 | * @var Variable 24 | */ 25 | std::unique_ptr _source; 26 | 27 | /** 28 | * The variable that will contain the key during the loop 29 | * @note This is not a requirement 30 | * @var Token 31 | */ 32 | std::unique_ptr _key; 33 | 34 | /** 35 | * The variable name that will contain the value during the loop 36 | * @var Token 37 | */ 38 | std::unique_ptr _value; 39 | 40 | /** 41 | * The statements to execute within the loop 42 | * @var Statements 43 | */ 44 | std::unique_ptr _statements; 45 | 46 | /** 47 | * The statements to execute when there are no elements to loop through 48 | * @var Statements 49 | */ 50 | std::unique_ptr _else_statements; 51 | 52 | public: 53 | /** 54 | * Constructor 55 | * @param target The variable to loop through 56 | * @param value Name of the value variable 57 | * @param statements The statements to execute in the foreach loop 58 | * @param else_statements The statements to be executed if there is nothing to loop through 59 | */ 60 | ForEachStatement(Variable *source, Token *value, Statements *statements, Statements *else_statements = nullptr) : 61 | _source(source), _value(value), _statements(statements), _else_statements(else_statements) {} 62 | 63 | /** 64 | * Constructor 65 | * @param target The variable to loop through 66 | * @param key Name of the key variable 67 | * @param value Name of the value variable 68 | * @param statements The statements to execute in the foreach loop 69 | * @param else_statements The statements to be executed if there is nothing to loop through 70 | */ 71 | ForEachStatement(Variable *source, Token *key, Token *value, Statements *statements, Statements *else_statements = nullptr) : 72 | _source(source), _key(key), _value(value), _statements(statements), _else_statements(else_statements) {} 73 | 74 | /** 75 | * Destructor 76 | */ 77 | virtual ~ForEachStatement() {} 78 | 79 | /** 80 | * Generate the output of this statement 81 | * @param generator 82 | */ 83 | void generate(Generator *generator) const override 84 | { 85 | // if there is no key, we pass an empty string 86 | if (_key == nullptr) generator->foreach(_source.get(), std::string(""), *_value, _statements.get(), _else_statements.get()); 87 | 88 | // otherwise we call the generator with a reference to the key 89 | else generator->foreach(_source.get(), *_key, *_value, _statements.get(), _else_statements.get()); 90 | } 91 | }; 92 | 93 | /** 94 | * End of namespace 95 | */ 96 | }} 97 | -------------------------------------------------------------------------------- /src/statements/if.h: -------------------------------------------------------------------------------- 1 | /** 2 | * IfStatement.h 3 | * 4 | * Class that represents an if-statement 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class IfStatement : public Statement 19 | { 20 | private: 21 | /** 22 | * The condition 23 | * @var Expression 24 | */ 25 | std::unique_ptr _expression; 26 | 27 | /** 28 | * The statements in the 'if' part 29 | * @var Statements 30 | */ 31 | std::unique_ptr _trueStatements; 32 | 33 | /** 34 | * The statements in the 'else' part 35 | * @var Statement 36 | */ 37 | std::unique_ptr _falseStatements; 38 | 39 | public: 40 | /** 41 | * Constructor 42 | * @param expression 43 | * @param statements 44 | */ 45 | IfStatement(Expression *expression, Statements *statements) : 46 | _expression(expression), _trueStatements(statements) {} 47 | 48 | /** 49 | * Constructor 50 | * @param expression 51 | * @param trueStatements 52 | * @param falseStatements 53 | */ 54 | IfStatement(Expression *expression, Statements *trueStatements, Statements *falseStatements) : 55 | _expression(expression), _trueStatements(trueStatements), _falseStatements(falseStatements) {} 56 | 57 | /** 58 | * Destructor 59 | */ 60 | virtual ~IfStatement() {} 61 | 62 | /** 63 | * Generate the output of this statement 64 | * @param generator 65 | */ 66 | void generate(Generator *generator) const override 67 | { 68 | // generate a condition statement 69 | generator->condition(_expression.get(), _trueStatements.get(), _falseStatements.get()); 70 | } 71 | }; 72 | 73 | /** 74 | * End namespace 75 | */ 76 | }} -------------------------------------------------------------------------------- /src/statements/raw.h: -------------------------------------------------------------------------------- 1 | /** 2 | * RawStatement.h 3 | * 4 | * Statement to simply echo raw output. Statements like this are created 5 | * for text that was not inside a {template} instruction. 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * Class definition 18 | */ 19 | class RawStatement : public Statement 20 | { 21 | private: 22 | /** 23 | * The raw data to be echo'ed 24 | * @var std::unique_ptr 25 | */ 26 | std::unique_ptr _data; 27 | 28 | public: 29 | /** 30 | * Constructor 31 | * @param token 32 | */ 33 | RawStatement(Token *token) : _data(token) {} 34 | 35 | /** 36 | * Destructor 37 | */ 38 | virtual ~RawStatement() {} 39 | 40 | /** 41 | * Generate the output of this statement 42 | * @param generator 43 | */ 44 | void generate(Generator *generator) const override 45 | { 46 | // add write instruction of raw data 47 | generator->raw(*_data); 48 | } 49 | }; 50 | 51 | /** 52 | * End of namespace 53 | */ 54 | }} -------------------------------------------------------------------------------- /src/statements/statement.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Statement.h 3 | * 4 | * Base class that is used by all statements 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Statement 19 | { 20 | protected: 21 | /** 22 | * Constructor 23 | * 24 | * This constructor is protected, because a statement is never constructed 25 | * by its own, but always through a derived class (like 'IfStatement') 26 | */ 27 | Statement() {} 28 | 29 | public: 30 | /** 31 | * Destructor 32 | */ 33 | virtual ~Statement() {} 34 | 35 | /** 36 | * Generate source code 37 | * 38 | * This method is passed a generator object that will be fed with all 39 | * input elements, and that will generate either the shared library or 40 | * the JIT representation. 41 | * 42 | * @param generator 43 | */ 44 | virtual void generate(Generator *generator) const = 0; 45 | 46 | }; 47 | 48 | /** 49 | * End namespace 50 | */ 51 | }} -------------------------------------------------------------------------------- /src/statements/statements.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Statements.h 3 | * 4 | * Class representing a list of statements 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class Statements : public Statement 19 | { 20 | private: 21 | /** 22 | * List of statements 23 | * @var std::list 24 | */ 25 | std::list> _statements; 26 | 27 | public: 28 | /** 29 | * Constructor 30 | */ 31 | Statements(); 32 | 33 | /** 34 | * Constructor with already the first statement 35 | * @param statement 36 | */ 37 | Statements(Statement *statement) 38 | { 39 | // add first statement 40 | add(statement); 41 | } 42 | 43 | /** 44 | * Function to add a statement to the list 45 | * @param statement 46 | */ 47 | void add(Statement *statement) 48 | { 49 | // add first statement 50 | _statements.emplace_back(statement); 51 | } 52 | 53 | /** 54 | * Generate source code 55 | * @param generator 56 | */ 57 | void generate(Generator *generator) const override 58 | { 59 | // loop through the statements, and output each one of them 60 | for (auto &statement : _statements) statement->generate(generator); 61 | } 62 | }; 63 | 64 | /** 65 | * End of namespace 66 | */ 67 | }} -------------------------------------------------------------------------------- /src/syntaxtree.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SyntaxTree.h 3 | * 4 | * Class representing the abstract syntax tree that describes the entire 5 | * template.tpl file. 6 | * 7 | * The private base class of the SyntaxTree is the TokenProcessor class, so 8 | * that it is possible to pass an instance of the syntax tree class to the 9 | * tokenizer. 10 | * 11 | * @author Emiel Bruijntjes 12 | * @copyright 2014 - 2017 Copernica BV 13 | */ 14 | 15 | /** 16 | * Set up namespace 17 | */ 18 | namespace SmartTpl { namespace Internal { 19 | 20 | /** 21 | * Class definition 22 | */ 23 | class SyntaxTree : public TokenProcessor 24 | { 25 | public: 26 | /** 27 | * Constructor 28 | * @param version Tokenizer version (1 for old and 2 for new) 29 | * @param buffer The buffer to parse 30 | * @param size Size of the buffer 31 | * @throws std::runtime_error in the case of an error 32 | */ 33 | SyntaxTree(size_t version, const char *buffer, size_t size) : TokenProcessor() 34 | { 35 | // check version number 36 | if (version == 1) 37 | { 38 | // use the old tokenizer 39 | v1::Tokenizer tokenizer; 40 | 41 | // pass the buffer to the tokenizer, it will pass all tokens to this syntaxtree object 42 | if (tokenizer.process(this, buffer, size)) return; 43 | 44 | // report the error 45 | throw CompileError(_error, tokenizer.getCurrentLine()); 46 | } 47 | else 48 | { 49 | // use the new tokenizer 50 | v2::Tokenizer tokenizer; 51 | 52 | // pass the buffer to the tokenizer, it will pass all tokens to this syntaxtree object 53 | if (tokenizer.process(this, buffer, size)) return; 54 | 55 | // report the error 56 | throw CompileError(_error, tokenizer.getCurrentLine()); 57 | } 58 | } 59 | 60 | /** 61 | * Destructor 62 | */ 63 | virtual ~SyntaxTree() {} 64 | 65 | /** 66 | * Generate the source code 67 | * @param generator The generator to use 68 | * @return bool False if we didn't have any statements to generate 69 | */ 70 | bool generate(Generator *generator) const 71 | { 72 | // skip if there are no statements 73 | if (!_statements) return false; 74 | 75 | // generate the statements 76 | _statements->generate(generator); 77 | 78 | // done 79 | return true; 80 | } 81 | }; 82 | 83 | /** 84 | * End namespace 85 | */ 86 | }} 87 | -------------------------------------------------------------------------------- /src/template.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Template.cpp 3 | * 4 | * Implementation of the Template class 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 - 2017 Copernica BV 8 | */ 9 | #include "includes.h" 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { 15 | 16 | /** 17 | * Constructor 18 | * @param source Source of the template to load 19 | */ 20 | Template::Template(const Source &source) 21 | { 22 | // is the source a shared library? 23 | if (source.library()) 24 | { 25 | // hey that's cool, we can create create a shard library 26 | _executor = new Internal::Library(source.name()); 27 | } 28 | else 29 | { 30 | // it was not a shared library, we're going to compile it into bytecode ourselves 31 | _executor = new Internal::Bytecode(source); 32 | } 33 | 34 | // Set the _encoding using the encoding() method on our executor 35 | _encoding = _executor->encoding(); 36 | } 37 | 38 | /** 39 | * Destructor 40 | */ 41 | Template::~Template() 42 | { 43 | // we no longer need the executor 44 | delete _executor; 45 | } 46 | 47 | /** 48 | * Is this template dependent on data to be personalised? 49 | * 50 | * @return Whether the template uses personalisationd ata 51 | */ 52 | bool Template::personalized() const 53 | { 54 | return _executor->personalized(); 55 | } 56 | 57 | /** 58 | * Get the template representation in C that can be compiled into a shared 59 | * object. This method only works for templates that were not already a 60 | * shared library. 61 | * 62 | * @return std::string 63 | */ 64 | std::string Template::compile() const 65 | { 66 | return _executor->compile(); 67 | } 68 | 69 | /** 70 | * Process the template, given a certain data source 71 | * 72 | * The data object that needs to be passed to this method is an object 73 | * that contains the values of all variables that can be user inside the 74 | * template. 75 | * 76 | * @param data Data source 77 | * @param outencoding The encoding that should be used for the output 78 | * @return std::string 79 | */ 80 | std::string Template::process(const Data &data, const std::string &outencoding) const 81 | { 82 | // we need a handler object 83 | Internal::Handler handler(&data, Internal::Escaper::get(outencoding)); 84 | 85 | // ask the executor to display the template 86 | _executor->process(handler); 87 | 88 | // In case our handler is set in failed mode we have to throw a runtime error 89 | if (handler.failed()) throw RunTimeError(handler.error()); 90 | 91 | // return the generated output string 92 | return handler.output(); 93 | } 94 | 95 | /** 96 | * End namespace 97 | */ 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/token.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Token.h 3 | * 4 | * Structure that holds the current token that is being processed by the 5 | * Tokenizer. Note that the Tokenizer is implemented in Tokenizer.yy 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { 15 | 16 | /** 17 | * The current parsed token 18 | */ 19 | class Token : public std::string 20 | { 21 | public: 22 | /** 23 | * Constructor 24 | * @param buffer 25 | * @param size 26 | */ 27 | Token(const char *buffer, size_t size) : std::string(buffer, size) {}; 28 | Token(const std::string &str) : std::string(str) {}; 29 | Token(std::string &&str) : std::string(std::move(str)) {}; 30 | Token(const char c) : std::string(1, c) {}; 31 | Token() : std::string() {}; 32 | 33 | /** 34 | * Destructor 35 | */ 36 | virtual ~Token() {} 37 | }; 38 | 39 | /** 40 | * End namespace 41 | */ 42 | }} -------------------------------------------------------------------------------- /src/tokenizer_v1.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Tokenizer_v1.h 3 | * 4 | * C++ class that tokenizes an input string, and that feeds the tokens to 5 | * the parser object 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 - 2017 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { namespace v1 { 15 | 16 | /** 17 | * Forward declarations 18 | */ 19 | class Parser; 20 | 21 | /** 22 | * Class definition 23 | */ 24 | class Tokenizer 25 | { 26 | private: 27 | /** 28 | * The scanner object 29 | * @var void* 30 | */ 31 | void *_scanner; 32 | 33 | /** 34 | * The line currently being processed 35 | */ 36 | int _line; 37 | 38 | /** 39 | * The current token 40 | */ 41 | Token* _token; 42 | 43 | public: 44 | /** 45 | * Constructor 46 | */ 47 | Tokenizer(); 48 | 49 | /** 50 | * Destructor 51 | */ 52 | virtual ~Tokenizer(); 53 | 54 | /** 55 | * Process a string, and feed all elements to the parser 56 | * @param parent Parser object that is notified about tokens 57 | * @param buffer The buffer to process 58 | * @param size Size of the buffer 59 | * @return true if parsing finished succesful, false otherwise 60 | */ 61 | bool process(TokenProcessor *parent, const char *buffer, size_t size); 62 | 63 | /** 64 | * Increase the line counter 65 | */ 66 | void increaseLine() { _line++; }; 67 | 68 | /** 69 | * Get the current line that we are/were at 70 | */ 71 | int getCurrentLine() const { return _line; }; 72 | 73 | /** 74 | * Change the current token to newToken 75 | */ 76 | void setCurrentToken(Token* newToken) { _token = newToken; }; 77 | 78 | /** 79 | * Returns the current token 80 | * @return Token* 81 | */ 82 | Token* token() const { return _token; }; 83 | }; 84 | 85 | /** 86 | * End of namespace 87 | */ 88 | }}} 89 | -------------------------------------------------------------------------------- /src/tokenizer_v2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Tokenizer_v2.h 3 | * 4 | * C++ class that tokenizes an input string, and that feeds the tokens to 5 | * the parser object 6 | * 7 | * @author Emiel Bruijntjes 8 | * @copyright 2014 - 2017 Copernica BV 9 | */ 10 | 11 | /** 12 | * Set up namespace 13 | */ 14 | namespace SmartTpl { namespace Internal { namespace v2 { 15 | 16 | /** 17 | * Forward declarations 18 | */ 19 | class Parser; 20 | 21 | /** 22 | * Class definition 23 | */ 24 | class Tokenizer 25 | { 26 | private: 27 | /** 28 | * The scanner object 29 | * @var void* 30 | */ 31 | void *_scanner; 32 | 33 | /** 34 | * The line currently being processed 35 | */ 36 | int _line; 37 | 38 | /** 39 | * The current token 40 | */ 41 | Token* _token; 42 | 43 | public: 44 | /** 45 | * Constructor 46 | */ 47 | Tokenizer(); 48 | 49 | /** 50 | * Destructor 51 | */ 52 | virtual ~Tokenizer(); 53 | 54 | /** 55 | * Process a string, and feed all elements to the parser 56 | * @param parent Parser object that is notified about tokens 57 | * @param buffer The buffer to process 58 | * @param size Size of the buffer 59 | * @return true if parsing finished succesful, false otherwise 60 | */ 61 | bool process(TokenProcessor *parent, const char *buffer, size_t size); 62 | 63 | /** 64 | * Increase the line counter 65 | */ 66 | void increaseLine() { _line++; }; 67 | 68 | /** 69 | * Get the current line that we are/were at 70 | */ 71 | int getCurrentLine() const { return _line; }; 72 | 73 | /** 74 | * Change the current token to newToken 75 | */ 76 | void setCurrentToken(Token* newToken) { _token = newToken; }; 77 | 78 | /** 79 | * Returns the current token 80 | * @return Token* 81 | */ 82 | Token* token() const { return _token; }; 83 | }; 84 | 85 | /** 86 | * End of namespace 87 | */ 88 | }}} 89 | -------------------------------------------------------------------------------- /src/tokenprocessor.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Parser.cpp 3 | * 4 | * Implementation file for the Parser class. 5 | * 6 | * @author Emiel Bruijntjes 7 | * @copyright 2014 Copernica BV 8 | */ 9 | #include "includes.h" 10 | 11 | /** 12 | * The following functions are implemented in the Lemon.cpp file, but that 13 | * file does not come with a header file, we redefine them here 14 | */ 15 | void *SmartTplParseAlloc(void *(*mallocProc)(size_t)); 16 | void SmartTplParseFree(void *p, void (*freeProc)(void*)); 17 | void SmartTplParse(void *yyp, int yymajor, SmartTpl::Internal::Token *token, SmartTpl::Internal::TokenProcessor *processor); 18 | 19 | /** 20 | * Set up namespace 21 | */ 22 | namespace SmartTpl { namespace Internal { 23 | 24 | /** 25 | * Constructor 26 | */ 27 | TokenProcessor::TokenProcessor() 28 | : _encoding(new Token("raw", 3)) { 29 | // allocate the the parser 30 | _resource = SmartTplParseAlloc(malloc); 31 | } 32 | 33 | /** 34 | * Destructor 35 | */ 36 | TokenProcessor::~TokenProcessor() 37 | { 38 | SmartTplParseFree(_resource, free); 39 | } 40 | 41 | /** 42 | * Called by the tokenizer when a token is detected 43 | * @param id Token identifier (see lemon.h) 44 | * @param token Additional token information 45 | * @return false if an error occured 46 | */ 47 | bool TokenProcessor::process(int id, Token *token) 48 | { 49 | // call the global Parse() function 50 | SmartTplParse(_resource, id, token, this); 51 | 52 | // return true if there was no error (empty), false otherwise 53 | return _error.empty(); 54 | } 55 | 56 | /** 57 | * End namespace 58 | */ 59 | }} -------------------------------------------------------------------------------- /src/vector_iterator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Vector_Iterator.h 3 | * 4 | * Iterator for VectorValues 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 - 2019 Copernica BV 8 | */ 9 | 10 | /** 11 | * Set up namespace 12 | */ 13 | namespace SmartTpl { namespace Internal { 14 | 15 | /** 16 | * Class definition 17 | */ 18 | class VectorIterator : public SmartTpl::Iterator 19 | { 20 | private: 21 | /** 22 | * The vector we're iterating over 23 | * @var std::vector 24 | */ 25 | const std::vector _vector; 26 | 27 | /** 28 | * Iterator to the current position in our vector 29 | * @var const_iterator 30 | */ 31 | std::vector::const_iterator _iter; 32 | 33 | /** 34 | * End iterator which indicates where we should stop 35 | * @var const_iterator 36 | */ 37 | const std::vector::const_iterator _end; 38 | 39 | /** 40 | * A simple counter so we can at least return some kind of key 41 | * @var integer_t 42 | */ 43 | integer_t _count; 44 | 45 | public: 46 | /** 47 | * Constructor 48 | */ 49 | VectorIterator(const std::vector &value) 50 | : _vector(value), 51 | _iter(_vector.begin()), 52 | _end(_vector.end()), 53 | _count(0) 54 | {} 55 | 56 | /** 57 | * Deconstructor 58 | */ 59 | virtual ~VectorIterator() {} 60 | 61 | /** 62 | * Check if the iterator is still valid 63 | * @return bool 64 | */ 65 | bool valid() const override 66 | { 67 | return _iter != _end; 68 | } 69 | 70 | /** 71 | * Move to the next position 72 | */ 73 | void next() override 74 | { 75 | ++_iter; 76 | ++_count; 77 | } 78 | 79 | /** 80 | * Retrieve pointer to the current member 81 | * @return Variant 82 | */ 83 | VariantValue value() const override 84 | { 85 | return *_iter; 86 | } 87 | 88 | /** 89 | * Retrieve a pointer to the current key 90 | * @return Variant 91 | */ 92 | VariantValue key() const override 93 | { 94 | return _count; 95 | } 96 | }; 97 | 98 | /** 99 | * End namespace 100 | */ 101 | }} 102 | -------------------------------------------------------------------------------- /src/vectorvalue.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * VectorValue.cpp 3 | * 4 | * A SmartTpl::Value which represents a vector with VariantValues 5 | * this is only a cpp file because the vector iterator is an internal class 6 | * 7 | * @author Toon Schoenmakers 8 | * @copyright 2014 Copernica BV 9 | */ 10 | #include "includes.h" 11 | 12 | /** 13 | * Set up namespace 14 | */ 15 | namespace SmartTpl { 16 | 17 | Iterator *VectorValue::iterator() const 18 | { 19 | return new Internal::VectorIterator(_value); 20 | } 21 | 22 | /** 23 | * End namespace 24 | */ 25 | } -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | test.out 4 | release-1.8.0.tar.gz 5 | googletest-release-1.8.0 6 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | COMPILER_FLAGS = -Wall -g -O0 -pipe -std=c++11 -Wno-sign-compare 2 | LINKER_FLAGS = 3 | INC = -I../ -I. -Igoogletest-release-1.8.0/googletest/include 4 | COMPILER = g++ 5 | LINKER = g++ 6 | 7 | VALGRIND = valgrind 8 | VALGRIND_OPTS = 9 | 10 | BINARY = test.out 11 | DEPS = $(patsubst %.cpp, %.o, $(shell find . -name \*.cpp -type f)) 12 | 13 | all: ${BINARY} 14 | 15 | %.o: %.cpp libgtest.a 16 | ${COMPILER} ${COMPILER_FLAGS} ${INC} -c $< -o $@ 17 | 18 | ${BINARY}: ${DEPS} main.cpp 19 | ${LINKER} ${LINKER_FLAGS} ${INC} -o ${BINARY} ${DEPS} libgtest.a -pthread ../libsmarttpl.so -ltimelib 20 | 21 | libgtest.a: 22 | wget -q https://github.com/google/googletest/archive/release-1.8.0.tar.gz 23 | tar -xf release-1.8.0.tar.gz 24 | ${COMPILER} ${COMPILER_FLAGS} -I googletest-release-1.8.0/googletest/include -I googletest-release-1.8.0/googletest -c googletest-release-1.8.0/googletest/src/gtest-all.cc 25 | ar -rv libgtest.a gtest-all.o 26 | 27 | .PHONY: test 28 | 29 | test: ${BINARY} 30 | ./${BINARY} 31 | 32 | .PHONY: valgrind 33 | 34 | valgrind: ${BINARY} 35 | ${VALGRIND} ${VALGRIND_OPTS} ./${BINARY} 36 | 37 | .PHONY: clean 38 | 39 | clean: 40 | rm -rf ${BINARY} ${DEPS} 41 | -------------------------------------------------------------------------------- /test/callbacks.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Callbacks.cpp 3 | * 4 | * Callback related unit tests 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | #include 11 | #include <../smarttpl.h> 12 | 13 | #include "ccode.h" 14 | 15 | using namespace SmartTpl; 16 | using namespace std; 17 | 18 | TEST(Callbacks, SimpleCallback) 19 | { 20 | string input("{$name}"); 21 | Template tpl((Buffer(input))); 22 | 23 | Data data; 24 | data.callback("name",[](){ return "Name"; }); 25 | 26 | string expectedOutput("Name"); 27 | EXPECT_EQ(expectedOutput, tpl.process(data)); 28 | 29 | if (compile(tpl)) // This will compile the Template into a shared library 30 | { 31 | Template library(File(SHARED_LIBRARY)); // Here we load that shared library 32 | EXPECT_EQ(expectedOutput, library.process(data)); 33 | } 34 | } 35 | 36 | TEST(Callbacks, CallbackCaching) 37 | { 38 | string input("{$name} {$name} {$nocache} {$nocache}"); 39 | Template tpl((Buffer(input))); 40 | 41 | { 42 | int counter = 0; 43 | int nocache = 0; 44 | Data data; 45 | data.callback("name", [&counter]() { 46 | counter++; 47 | return "Name"; 48 | }, true) 49 | .callback("nocache", [&nocache]() { 50 | nocache++; 51 | return "NoCache"; 52 | }); 53 | 54 | string expectedOutput("Name Name NoCache NoCache"); 55 | EXPECT_EQ(expectedOutput, tpl.process(data)); 56 | EXPECT_EQ(counter, 1); 57 | EXPECT_EQ(nocache, 2); // Should be called twice, as it is printed twice. This essentially tests if size() is cached 58 | } 59 | 60 | if (compile(tpl)) // This will compile the Template into a shared library 61 | { 62 | Template library(File(SHARED_LIBRARY)); // Here we load that shared library 63 | int counter = 0; 64 | int nocache = 0; 65 | Data data; 66 | data.callback("name", [&counter]() { 67 | counter++; 68 | return "Name"; 69 | }, true) 70 | .callback("nocache", [&nocache]() { 71 | nocache++; 72 | return "NoCache"; 73 | }); 74 | 75 | string expectedOutput("Name Name NoCache NoCache"); 76 | EXPECT_EQ(expectedOutput, library.process(data)); 77 | EXPECT_EQ(counter, 1); 78 | EXPECT_EQ(nocache, 2); // Should be called twice, as it is printed twice. This essentially tests if size() is cached 79 | } 80 | } 81 | 82 | TEST(Callbacks, Counter) 83 | { 84 | string input("{$i} {$i} {$i} {$i} {$i}"); 85 | Template tpl((Buffer(input))); 86 | 87 | int counter = 0; 88 | Data data; 89 | data.callback("i", [&counter]() { 90 | return ++counter; 91 | }); 92 | 93 | string expectedOutput("1 2 3 4 5"); 94 | EXPECT_EQ(expectedOutput, tpl.process(data)); 95 | EXPECT_EQ(5, counter); 96 | 97 | if (compile(tpl)) // This will compile the Template into a shared library 98 | { 99 | Template library(File(SHARED_LIBRARY)); // Here we load that shared library 100 | counter = 0; // Reset our counter 101 | 102 | EXPECT_EQ(expectedOutput, library.process(data)); 103 | EXPECT_EQ(5, counter); 104 | } 105 | } -------------------------------------------------------------------------------- /test/ccode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * CCode.h 3 | * 4 | * Contains a method to not only generate the C code, but also attempt to 5 | * compile it. 6 | * 7 | * @author Toon Schoenmakers 8 | * @copyright 2014 Copernica BV 9 | */ 10 | 11 | #pragma once 12 | 13 | #define SHARED_LIBRARY "/tmp/test.so" 14 | 15 | #include 16 | #include <../smarttpl.h> 17 | 18 | using namespace SmartTpl; 19 | using namespace std; 20 | 21 | extern bool no_clang; 22 | extern bool no_gcc; 23 | 24 | /** 25 | * Tries to compile a template to a shared library 26 | * It will compile the template with both gcc and clang, in both cases it'll 27 | * compile it with "-Wall -Werror", so no warnings allowed! If it succesfully 28 | * compiled you can load the shared library by loading the file SHARED_LIBRARY. 29 | * If you want to run the unittests without compiling the templates into shared 30 | * libraries simply run with NO_COMPILE in your enviroment variables 31 | * @param tpl The template to actually compile 32 | * @return true if succesfully compiled, false otherwise 33 | */ 34 | inline bool compile(const Template &tpl) 35 | { 36 | if (getenv("NO_COMPILE")) return false; 37 | 38 | int gccret = -1; 39 | int clangret = -1; 40 | 41 | if (no_gcc == false) 42 | { 43 | FILE *gccshell = popen("gcc -x c -pipe -Wall -Werror -fPIC -shared -nostdlib -O3 -o " SHARED_LIBRARY " -", "w"); 44 | EXPECT_TRUE(gccshell != NULL) << strerror(errno); 45 | if (gccshell) 46 | { 47 | fprintf(gccshell, "%s", tpl.compile().c_str()); 48 | gccret = pclose(gccshell); 49 | EXPECT_EQ(0, gccret) << "gcc failed to compile this template"; 50 | } 51 | } 52 | 53 | if (no_clang == false) 54 | { 55 | FILE *clangshell = popen("clang -x c -pipe -Wall -Werror -fbracket-depth=1024 -fPIC -shared -nostdlib -O3 -o " SHARED_LIBRARY " -", "w"); 56 | EXPECT_TRUE(clangshell != NULL) << strerror(errno); 57 | if (clangshell) 58 | { 59 | fprintf(clangshell, "%s", tpl.compile().c_str()); 60 | clangret = pclose(clangshell); 61 | EXPECT_EQ(0, clangret) << "clang failed to compile this template"; 62 | } 63 | } 64 | 65 | return gccret == 0 || clangret == 0; 66 | } -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Main.cpp 3 | * 4 | * Start point of the unit tests 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include "ccode.h" 14 | 15 | bool no_clang = false; 16 | bool no_gcc = false; 17 | 18 | static const struct option opts[] = { 19 | { "help", no_argument, 0, 'h' }, // Print a basic help 20 | { "no-clang", no_argument, 0, 'c' }, // Don't compile tests with clang 21 | { "no-gcc", no_argument, 0, 'g' }, // Don't compile tests with gcc 22 | { "no-compile", no_argument, 0, 'C' }, // Don't compile tests at all 23 | { 0, 0, 0, 0 } 24 | }; 25 | 26 | int main(int argc, char** argv) { 27 | ::testing::InitGoogleTest(&argc, argv); 28 | ::testing::FLAGS_gtest_shuffle = true; 29 | int arg, optindex; 30 | while ((arg = getopt_long(argc, argv, "gcCh", opts, &optindex)) != -1) 31 | { 32 | switch (arg) { 33 | case 'c': 34 | no_clang = true; 35 | break; 36 | case 'g': 37 | no_gcc = true; 38 | break; 39 | case 'C': 40 | no_clang = true; 41 | no_gcc = true; 42 | break; 43 | case 'h': 44 | default: 45 | std::cout << " --no-clang Don't compile tests with clang" << std::endl 46 | << " --no-gcc Don't compile tests with gcc" << std::endl 47 | << " --no-compile Don't try to compile tests at all" << std::endl; 48 | return EXIT_FAILURE; 49 | } 50 | } 51 | if (no_gcc == false) { 52 | int gcc = system("gcc --version"); 53 | no_gcc = (!WEXITSTATUS(gcc) == 0); 54 | } 55 | if (no_clang == false) { 56 | int clang = system("clang --version"); 57 | no_clang = (!WEXITSTATUS(clang) == 0); 58 | } 59 | return RUN_ALL_TESTS(); 60 | }; -------------------------------------------------------------------------------- /test/stress.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Stress.cpp 3 | * 4 | * Stress tests, these are purely here to test the limits of the SMART-TPL library 5 | * 6 | * @author Toon Schoenmakers 7 | * @copyright 2014 Copernica BV 8 | */ 9 | 10 | #include 11 | #include <../smarttpl.h> 12 | 13 | #include "ccode.h" 14 | 15 | using namespace SmartTpl; 16 | using namespace std; 17 | 18 | /** 19 | * This test will attempt to compile about 1000 chained modifiers, which should 20 | * succeed just fine. It can go higher just fine (without causing stack overflow) 21 | * but that increases the time of this time by quite a bit. 22 | */ 23 | TEST(Stress, ChainedModifiers) 24 | { 25 | string input("{$var"); 26 | for (int i = 0; i < 500; ++i) input.append("|upper|lower"); 27 | input.push_back('}'); 28 | Template tpl((Buffer(input))); 29 | 30 | Data data; 31 | data.assign("var", "VaRiAbLe"); 32 | 33 | string expectedOutput("variable"); 34 | EXPECT_EQ(expectedOutput, tpl.process(data)); 35 | 36 | if (compile(tpl)) // This will compile the Template into a shared library 37 | { 38 | Template library(File(SHARED_LIBRARY)); // Here we load that shared library 39 | EXPECT_EQ(expectedOutput, library.process(data)); 40 | } 41 | } 42 | 43 | /** 44 | * The following tests should cause stack overflows 45 | */ 46 | TEST(Stress, ElseIfStatements) 47 | { 48 | string input("{if true}\necho\n"); 49 | for (int i = 0; i < 10000; ++i) input.append("{elseif true}\n"); 50 | input.append("{/if}"); 51 | EXPECT_THROW(Template tpl((Buffer(input))), std::runtime_error); 52 | } 53 | 54 | TEST(Stress, InnerForEachLoops) 55 | { 56 | string input; 57 | for (int i = 0; i < 10000; ++i) input.append("{foreach $map as $key => $value}"); 58 | for (int i = 0; i < 10000; ++i) input.append("{/foreach}"); 59 | EXPECT_THROW(Template tpl((Buffer(input))), std::runtime_error); 60 | } --------------------------------------------------------------------------------