From 83f37645d9c2e934df3cfc2c79fe8d0fd4d67094 Mon Sep 17 00:00:00 2001 From: hama Date: Thu, 7 Aug 2014 23:57:12 +0200 Subject: [PATCH] dayly work --- rplcore/rplbytestorage.cpp | 162 ++++++++++++++++++++++++++++++ rplcore/rplbytestorage.hpp | 46 +++++++++ rplcore/rplcore.hpp | 1 + rplexpr/rplasclasses.cpp | 78 ++++++++++---- rplexpr/rplasclasses.hpp | 9 +- rplexpr/rplastree.cpp | 27 +++-- rplexpr/rplastree.hpp | 8 +- rplexpr/rpllexer.cpp | 5 +- rplexpr/rplvm.cpp | 27 +++-- rplexpr/rplvm.hpp | 3 +- rplexpr/rplvm_test.cpp | 3 +- rplstatic/rplstatic.pro | 6 +- test/rplmfparser/baseTest.txt | 2 +- test/rplmfparser/defTest.txt | 2 +- test/rplmfparser/field1.txt | 2 +- test/rplmfparser/forC1.txt | 2 +- test/rplmfparser/forC2.txt | 2 +- test/rplmfparser/forIt1.txt | 2 +- test/rplmfparser/ifTest1.txt | 2 +- test/rplmfparser/ifTest2.txt | 2 +- test/rplmfparser/list1.txt | 2 +- test/rplmfparser/list2.txt | 2 +- test/rplmfparser/map1.txt | 2 +- test/rplmfparser/map2.txt | 2 +- test/rplmfparser/meth1.txt | 2 +- test/rplmfparser/meth2.txt | 2 +- test/rplmfparser/meth3.txt | 2 +- test/rplmfparser/meth4.txt | 2 +- test/rplmfparser/methc1.txt | 2 +- test/rplmfparser/opTest1.txt | 2 +- test/rplmfparser/repeatTest.txt | 2 +- test/rplmfparser/whileTest.txt | 2 +- unittests/main.cpp | 2 + unittests/rplbytestorage_test.cpp | 73 ++++++++++++++ unittests/unittests.pro | 5 +- 35 files changed, 428 insertions(+), 67 deletions(-) create mode 100644 rplcore/rplbytestorage.cpp create mode 100644 rplcore/rplbytestorage.hpp create mode 100644 unittests/rplbytestorage_test.cpp diff --git a/rplcore/rplbytestorage.cpp b/rplcore/rplbytestorage.cpp new file mode 100644 index 0000000..0230073 --- /dev/null +++ b/rplcore/rplbytestorage.cpp @@ -0,0 +1,162 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + + +#include "rplcore/rplcore.hpp" + +/** @class RplByteStorage rplbytestorage.hpp "rplcore/rplbytestorage.hpp" + * + * @brief Implements a very efficient byte storage. + * + * Efficiency: Allocation of one block needs mostly only 1 comparison + * and 2 assignments. + * + * Restriction: The blocks can be returned (freed) only once, not block by block. + * This can be an advantage! + * + * Process: + * The storage administrates large buffers. Allocation can be done only in the + * last buffer. If the buffer has too little space for the new block a new + * buffer will be allocated and linked into the buffer list. + * One buffer can store dozens or hundreds of blocks. Therefore allocation and + * freeing is much cheeper than allocation by new(). + */ + +/** + * @brief Constructor. + * + * @param bufferSize the size of one buffer + */ +RplByteStorage::RplByteStorage(int bufferSize) : + m_bufferSize(bufferSize), + m_buffer(NULL), + m_rest(0), + m_freePosition(NULL), + m_summarySize(0), + m_buffers(0) +{ +} + +/** + * @brief Destructor. + */ +RplByteStorage::~RplByteStorage() +{ + const uint8_t* ptr = m_buffer; + while(ptr != NULL){ + const uint8_t* old = ptr; + ptr = *(const uint8_t**)(ptr); + delete[] old; + m_buffers--; + } + assert(m_buffers == 0); +} + +/** + * @brief Allocates a block in a new allocated buffer. + * + * This method will be called if the buffer has too little space. + * A new buffer will be allocated and the block will be allocated + * in this new block. + * + * @note The block address is returned, but the allocation must be done outside! + * + * @param size of the new block (inclusive the trailing '\0') + * @return a new block with the size bytes + */ +char* RplByteStorage::allocBuffer(int size) +{ + m_rest = size + sizeof(uint8_t*) <= (size_t) m_bufferSize + ? m_bufferSize : size + sizeof(uint8_t*); + m_summarySize += m_rest; + m_buffers++; + uint8_t* rc = new uint8_t[m_rest]; + * (uint8_t**)rc = m_buffer; + m_buffer = rc; + rc += sizeof(uint8_t*); + // the block allocation will be done outside! + m_freePosition = rc; + m_rest -= sizeof(uint8_t*); + return reinterpret_cast(rc); +} + +/** + * @brief Duplicates a string into a new allocated block. + * + * @param source the source string + * @param size the length of the string. + * If < 0 strlen(source) will be used + * @return a copy of the source string. The copy ends always with '\0' + */ +const char* RplByteStorage::allocateChars(const char* source, int size) +{ + if (size < 0) + size = strlen(source); + const char* rc = allocateChars(size + 1); + memcpy((void*) rc, source, size); + ((char*)rc)[size] = '\0'; + return rc; +} + +/** + * @brief Duplicates a string into a new allocated block. + * + * The unicode string will be converted into a UTF-8 string. + * + * @param source the source string + * @return a copy of the source string. The copy ends always with '\0' + */ +const char* RplByteStorage::allocUtf8(const QString& source) +{ + const char* rc = allocateChars(source.toUtf8().constData()); + return rc; +} + +/** + * @brief Allocates a byte block without initialization. + * + * @param size the size of the block to allocate + * + * @return a byte block (without a trailing '\0') + */ +uint8_t* RplByteStorage::allocateBytes(int size) +{ + uint8_t* rc = size <= m_rest ? m_freePosition + : reinterpret_cast(allocBuffer(size)); + m_freePosition += size; + m_rest -= size; + return rc; +} + +/** + * @brief Allocates a byte block initialized by '\0'. + * + * @param size the size of the block to allocate + * + * @return a byte block (without a trailing '\0') + */ +uint8_t* RplByteStorage::allocateZeros(int size) +{ + uint8_t* rc = allocateBytes(size); + memset(rc, 0, size); + return rc; +} + +/** + * @brief Allocates a byte block. + * + * @param size the size of the block to allocate + * + * @return a byte block (without a trailing '\0') + */ +uint8_t* RplByteStorage::allocateBytes(void* source, int size) +{ + uint8_t* rc = allocateBytes(size); + memcpy(rc, source, size); + return rc; +} diff --git a/rplcore/rplbytestorage.hpp b/rplcore/rplbytestorage.hpp new file mode 100644 index 0000000..41e0a9c --- /dev/null +++ b/rplcore/rplbytestorage.hpp @@ -0,0 +1,46 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + + +#ifndef RPLCHARSTORAGE_HPP +#define RPLCHARSTORAGE_HPP + +class RplByteStorage +{ +public: + RplByteStorage(int blockSize); + ~RplByteStorage(); +public: + char* allocBuffer(int size); + /** + * @brief Allocates a char block. + * + * @return a new block + */ + inline char* allocateChars(int size){ + char* rc = size <= m_rest ? (char*) m_freePosition + : allocBuffer(size); + m_freePosition += size; + m_rest -= size; + return rc; + } + const char* allocateChars(const char* source, int size = -1); + const char* allocUtf8(const QString& source); + uint8_t* allocateBytes(int size); + uint8_t* allocateZeros(int size); + uint8_t*allocateBytes(void* source, int size); +private: + int m_bufferSize; + uint8_t* m_buffer; + int m_rest; + uint8_t* m_freePosition; + qint64 m_summarySize; + int m_buffers; +}; + +#endif // RPLCHARSTORAGE_HPP diff --git a/rplcore/rplcore.hpp b/rplcore/rplcore.hpp index 168232c..f58b0c6 100644 --- a/rplcore/rplcore.hpp +++ b/rplcore/rplcore.hpp @@ -34,6 +34,7 @@ typedef unsigned char uint8_t; #define RPL_UNUSED(x) (void)(x) #include "rplmodules.hpp" +#include "rplcore/rplbytestorage.hpp" #include "rplcore/rpllogger.hpp" #include "rplcore/rplexception.hpp" #include "rplcore/rplcontainer.hpp" diff --git a/rplexpr/rplasclasses.cpp b/rplexpr/rplasclasses.cpp index 446087d..04201ab 100644 --- a/rplexpr/rplasclasses.cpp +++ b/rplexpr/rplasclasses.cpp @@ -19,6 +19,9 @@ RplASBoolean* RplASBoolean::m_instance = NULL; RplASVoid* RplASVoid::m_instance = NULL; RplASFormula* RplASFormula::m_instance = NULL; +///@ToDo static +///RplSymbolSpace* RplSymbolSpace::m_global = NULL; + /** @class RplSymbolSpace rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements a symbol space for the parser. @@ -40,37 +43,48 @@ RplASFormula* RplASFormula::m_instance = NULL; * Each class defines a symbol space and takes the symbol space of the superclass * as its parent. If there is no superclass the module's symbol space will be taken. * - * Each method defines its own symbol space. The parent may be the symbol space of - * the module or of the class. + * Each method defines its own symbol space. The parent may be the symbol space + * of the module or of the class. */ - +/** + * @brief Constructor, only for the global symbol space. + * + * @param name the symbol space's name + * @param parent the parent of the symbol space + */ +RplSymbolSpace::RplSymbolSpace(RplASTree& tree) : + m_type(SST_GLOBAL), + m_name("$global"), + m_variables(), + m_classes(), + m_parent(NULL), + m_body(NULL), + m_listOfVars(), + m_tree(tree) +{ +} /** * @brief Constructor. * + * @param type the type of the symbol space: SST_MODULE, ... * @param name the symbol space's name * @param parent the parent of the symbol space */ RplSymbolSpace::RplSymbolSpace(RplSymbolSpace::SymbolSpaceType type, - const QString &name, RplSymbolSpace *parent) : + const QString& name, + RplSymbolSpace* parent) : m_type(type), m_name(name), m_variables(), m_classes(), m_parent(parent), - m_body(NULL) -{ - if (type == SST_GLOBAL){ - m_classes[RplASInteger::m_instance->name()] = RplASInteger::m_instance; - m_classes[RplASBoolean::m_instance->name()] = RplASBoolean::m_instance; - m_classes[RplASFloat::m_instance->name()] = RplASFloat::m_instance; - m_classes[RplASString::m_instance->name()] = RplASString::m_instance; - m_classes[RplASList::m_instance->name()] = RplASList::m_instance; - m_classes[RplASMap::m_instance->name()] = RplASMap::m_instance; - m_classes[RplASVoid::m_instance->name()] = RplASVoid::m_instance; - m_classes[RplASFormula::m_instance->name()] = RplASFormula::m_instance; - } + m_body(NULL), + m_listOfVars(), + m_tree(parent->m_tree) +{ } + /** * @brief Destructor. */ @@ -196,7 +210,8 @@ void RplSymbolSpace::dump(FILE* fp, int indent, const char* header) * @param type type to inspect * @return the name of the type */ -const char*RplSymbolSpace::spaceTypeName(RplSymbolSpace::SymbolSpaceType type) +const char*RplSymbolSpace::spaceTypeName( + RplSymbolSpace::SymbolSpaceType type) { const char* rc = NULL; switch(type){ @@ -221,6 +236,35 @@ const char*RplSymbolSpace::spaceTypeName(RplSymbolSpace::SymbolSpaceType type) } return rc; } + +/** + * @brief Initilizes the global symbol space. + * + * @param tree the abstract syntax tree + * @return the global symbol space + */ +RplSymbolSpace* RplSymbolSpace::createGlobal(RplASTree& tree) +{ + RplSymbolSpace* rc = new RplSymbolSpace(tree); + rc->m_tree = tree; + RplASInteger::m_instance = new RplASInteger(tree); + rc->m_classes[RplASInteger::m_instance->name()] = RplASInteger::m_instance; + RplASBoolean::m_instance = new RplASBoolean(tree); + rc->m_classes[RplASBoolean::m_instance->name()] = RplASBoolean::m_instance; + RplASFloat::m_instance = new RplASFloat(tree); + rc->m_classes[RplASFloat::m_instance->name()] = RplASFloat::m_instance; + RplASString::m_instance = new RplASString(tree); + rc->m_classes[RplASString::m_instance->name()] = RplASString::m_instance; + RplASList::m_instance = new RplASList(tree); + rc->m_classes[RplASList::m_instance->name()] = RplASList::m_instance; + RplASMap::m_instance = new RplASMap(tree); + rc->m_classes[RplASMap::m_instance->name()] = RplASMap::m_instance; + RplASVoid::m_instance = new RplASVoid(tree); + rc->m_classes[RplASVoid::m_instance->name()] = RplASVoid::m_instance; + RplASFormula::m_instance = new RplASFormula(tree); + rc->m_classes[RplASFormula::m_instance->name()] = RplASFormula::m_instance; + return rc; +} /** * @brief Returns the list of the variables. * diff --git a/rplexpr/rplasclasses.hpp b/rplexpr/rplasclasses.hpp index 02c3fd0..05ffd1a 100644 --- a/rplexpr/rplasclasses.hpp +++ b/rplexpr/rplasclasses.hpp @@ -26,6 +26,7 @@ protected: }; class RplASUserClass; +class RplASTree; class RplSymbolSpace { public: @@ -42,6 +43,8 @@ public: typedef QMap ClassMap; typedef QMap MethodMap; typedef QList VariableList; +private: + RplSymbolSpace(RplASTree& tree); public: RplSymbolSpace(SymbolSpaceType type, const QString& name, RplSymbolSpace* parent); @@ -60,8 +63,8 @@ public: RplSymbolSpace* parent() const; VariableList listOfVars() const; public: - static void initGlobal(RplSymbolSpace& global); static const char* spaceTypeName(SymbolSpaceType type); + static RplSymbolSpace* createGlobal(RplASTree& tree); private: SymbolSpaceType m_type; QString m_name; @@ -71,9 +74,7 @@ private: RplSymbolSpace* m_parent; RplASItem* m_body; VariableList m_listOfVars; - -public: - static RplSymbolSpace m_global; + RplASTree& m_tree; }; class RplASBoolean : public RplASClass { diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp index 8b1638a..55a1bdc 100644 --- a/rplexpr/rplastree.cpp +++ b/rplexpr/rplastree.cpp @@ -104,8 +104,13 @@ RplASException::RplASException() : /** @class RplASVariant rplastree.hpp "rplexpr/rplastree.hpp" * - * @brief Implements a class which can be one of the basic types. + * @brief Implements a class which can hold the value of any type. * + * The VM uses some tricks (performance): Therefore this class + * must not be virtual! + */ +/** + * @brief Constructor. */ RplASVariant::RplASVariant() : m_variantType(VT_UNDEF), @@ -660,7 +665,7 @@ RplASMapConstant::RplASMapConstant() : * @param value IN/OUT: the value of the instance * @return NULL */ -RplASNode1* RplASMapConstant::calc(RplASVariant& value) +RplASNode1* RplASMapConstant::calc(RplASVariant& ) { // ToDo: copy map: //value = m_value; @@ -755,7 +760,7 @@ const QString& RplASNamedValue::name() const * @param value In/OUT: the value of the instance * @return NULL */ -RplASNode1* RplASNamedValue::calc(RplASVariant& value, RplStackFrame* frame) +RplASNode1* RplASNamedValue::calc(RplASVariant& , RplStackFrame* ) { return NULL; } @@ -1770,11 +1775,11 @@ void RplASClass::setSymbols() * @brief Constructor. */ RplASTree::RplASTree() : - // freed in ~RplASTree() - m_global(new RplSymbolSpace(RplSymbolSpace::SST_GLOBAL, "global", NULL)), + m_global(NULL), m_modules(), m_symbolSpaces(), - m_currentSpace(NULL) + m_currentSpace(NULL), + m_store(128*1024) { init(); } @@ -1794,6 +1799,7 @@ RplASTree::~RplASTree() */ void RplASTree::init() { + m_global = RplSymbolSpace::createGlobal(*this); m_symbolSpaces.append(m_global); m_currentSpace = m_global; } @@ -1809,6 +1815,15 @@ void RplASTree::destroy() } m_symbolSpaceHeap.clear(); } +/** + * @brief Returns the string storage of the instance. + * + * @return the efficient allocator for C strings + */ +RplByteStorage& RplASTree::store() +{ + return m_store; +} /** * @brief Handles the start of a new module. diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp index 4ff89a8..2e21c12 100644 --- a/rplexpr/rplastree.hpp +++ b/rplexpr/rplastree.hpp @@ -55,6 +55,9 @@ class RplASItem; class RplASCondition; class RplASVariant { + /* The VM uses some tricks (performance): Therefore this class + * must not be virtual! + */ public: enum VariantType { VT_UNDEF, @@ -113,7 +116,7 @@ public: enum NodeFlags { NF_UNDEF, /// the node calculates a value: - VF_CALCULABLE = 1 << 1, + NF_CALCULABLE = 1 << 1, /// the tree under this node is complete checked for data type correctness NF_TYPECHECK_COMPLETE = 1 << 2, /// debugger: this node is a breakpoint @@ -596,6 +599,8 @@ public: const char* header = NULL); RplSymbolSpace*findmodule(const QString& name); RplSourcePosition* copyPosition(); + RplByteStorage& store(); + protected: void init(); void destroy(); @@ -610,6 +615,7 @@ private: RplSymbolSpace* m_currentSpace; // contain all ever built symbol spaces: SymbolSpaceMap m_symbolSpaceHeap; + RplByteStorage m_store; }; #endif // RPLASTREE_HPP diff --git a/rplexpr/rpllexer.cpp b/rplexpr/rpllexer.cpp index 0080407..e8738cf 100644 --- a/rplexpr/rpllexer.cpp +++ b/rplexpr/rpllexer.cpp @@ -850,7 +850,6 @@ const RplSourcePosition* RplLexer::currentPosition() const RplToken* RplLexer::nextToken() { RplToken* rc = NULL; - const RplSourcePosition* waitingPosition = NULL; int ix; if (m_waitingToken != NULL){ rc = m_currentToken = m_waitingToken; @@ -874,7 +873,7 @@ RplToken* RplLexer::nextToken() QChar cc = m_input.at(0); int cc2 = cc.unicode(); if (cc.isSpace()){ - waitingPosition = m_currentPosition; + //waitingPosition = m_currentPosition; m_currentToken->m_tokenType = TOKEN_SPACE; ix = 1; while(ix < m_input.size() && m_input.at(ix).isSpace()) @@ -902,7 +901,7 @@ RplToken* RplLexer::nextToken() CC_2nd_COMMENT_START, m_commentStarts); if (rc != NULL) scanComment(); - waitingPosition = m_currentPosition; + //waitingPosition = m_currentPosition; } if (rc == NULL && (m_charInfo[cc2] & CC_FIRST_OP)){ diff --git a/rplexpr/rplvm.cpp b/rplexpr/rplvm.cpp index 47ddbb6..176a44d 100644 --- a/rplexpr/rplvm.cpp +++ b/rplexpr/rplvm.cpp @@ -52,7 +52,7 @@ RplStackFrame::RplStackFrame(RplSymbolSpace* symbols) : m_variables(NULL), m_symbols(symbols) { - if (m_countLocals > 0) + if (m_countVariables > 0) m_variables = new RplASVariant[m_countVariables]; } @@ -76,7 +76,7 @@ RplASVariant& RplStackFrame::valueOfVariable(int index) { if (index < 0 || index >= m_countVariables) throw RplVmException("valueOfVariable(): invalid index: %d", index); - return *m_listOfVariables[index]; + return m_variables[index]; } /** @class RplVMThread rplvm.hpp "rplexpr/rplvm.hpp" @@ -116,10 +116,11 @@ void RplVMThread::execute(RplASNode1* statements, RplSymbolSpace* space) bool debugMode = m_debugMode; while(statements != NULL){ if (debugMode - && (m_singleStep || (statement->flags() & NF_BREAKPOINT) != 0)) + && (m_singleStep + || (statements->flags() & RplASItem::NF_BREAKPOINT) != 0)) debug(statements); RplASCalculable* statement = dynamic_cast(statements); - statement->calc(&m_currentValue); + statement->calc(m_currentValue); } } @@ -139,15 +140,17 @@ void RplVMThread::debug(RplASNode1* statement) * * This is a execution unit which interprets an abstract syntax tree. */ -RplVirtualMachine::RplVirtualMachine(RplASTree* tree, RplSource* source, +RplVirtualMachine::RplVirtualMachine(RplASTree& tree, RplSource& source, int maxStack) : m_maxStack(maxStack), m_threads(), m_flags(VF_UNDEF), m_source(source), - m_tree(tree) + m_tree(tree), + m_trace() { m_threads.reserve(8); + m_trace.reserve(1024); } /** @@ -190,13 +193,14 @@ void RplVirtualMachine::addThread(RplASItem* initialization, int maxStack) { RplVMThread* thread = new RplVMThread( - maxThread <= 0 ? m_maxStack : maxStack, self); + maxStack <= 0 ? m_maxStack : maxStack, this); m_threads.append(thread); if (initialization != NULL){ - thread->execute(initialization, spaceInitialization); + thread->execute(dynamic_cast(initialization), + spaceInitialization); } if (statements != NULL) - thread->execute(statements, space); + thread->execute(dynamic_cast(statements), space); } /** * @brief Tests whether a given flag is set. @@ -208,6 +212,7 @@ void RplVirtualMachine::addThread(RplASItem* initialization, bool RplVirtualMachine::hasFlag(RplVirtualMachine::VMFlag flag) const { bool rc = (m_flags & flag) != 0; + return rc; } /** * @brief Adds a flag to the current flags. @@ -217,7 +222,7 @@ bool RplVirtualMachine::hasFlag(RplVirtualMachine::VMFlag flag) const */ void RplVirtualMachine::setFlag(RplVirtualMachine::VMFlag flag) { - m_flag |= flag; + m_flags |= flag; } /** @@ -228,5 +233,5 @@ void RplVirtualMachine::setFlag(RplVirtualMachine::VMFlag flag) */ void RplVirtualMachine::clearFlag(RplVirtualMachine::VMFlag flag) { - m_flag &= ~flag; + m_flags &= ~flag; } diff --git a/rplexpr/rplvm.hpp b/rplexpr/rplvm.hpp index 24eeb37..4134935 100644 --- a/rplexpr/rplvm.hpp +++ b/rplexpr/rplvm.hpp @@ -55,7 +55,7 @@ public: VF_TRACE_AUTO_VARIABLES = 1<<3 }; - + typedef QList LineList; public: RplVirtualMachine(RplASTree& tree, RplSource& source, int maxStack = 1024); public: @@ -73,6 +73,7 @@ private: int m_flags; RplSource& m_source; RplASTree& m_tree; + LineList m_trace; }; #endif // RPLVM_HPP diff --git a/rplexpr/rplvm_test.cpp b/rplexpr/rplvm_test.cpp index 6c194f0..05acac0 100644 --- a/rplexpr/rplvm_test.cpp +++ b/rplexpr/rplvm_test.cpp @@ -45,8 +45,9 @@ private: fnExpected += (char) QDir::separator().toLatin1(); fnExpected += fileExpected; QByteArray fnCurrent = getTempFile(fileExpected, "rplvm"); + vm.setFlag(RplVirtualMachine::VF_TRACE_STATEMENTS); vm.executeModule(""); - vm.dump(fnCurrent, RplASTree::DMP_NO_GLOBALS); + //vm.dump(fnCurrent, RplASTree::DMP_NO_GLOBALS); assertEqualFiles(fnExpected.constData(), fnCurrent.constData(), __FILE__, lineNo); } diff --git a/rplstatic/rplstatic.pro b/rplstatic/rplstatic.pro index 19d3f14..7368212 100644 --- a/rplstatic/rplstatic.pro +++ b/rplstatic/rplstatic.pro @@ -37,7 +37,8 @@ SOURCES += \ ../rplexpr/rplasclasses.cpp \ ../rplexpr/rplmfparser.cpp \ ../rplexpr/rplvm.cpp \ - ../rplexpr/rplparser.cpp + ../rplexpr/rplparser.cpp \ + ../rplcore/rplbytestorage.cpp HEADERS += ../rplmodules.hpp \ ../rplcore/rplconfig.hpp \ @@ -66,7 +67,8 @@ HEADERS += ../rplmodules.hpp \ ../rplexpr/rplasclasses.hpp \ ../rplexpr/rplmfparser.hpp \ ../rplexpr/rplvm.hpp \ - ../rplexpr/rplparser.hpp + ../rplexpr/rplparser.hpp \ + ../rplcore/rplbytestorage.hpp unix:!symbian { maemo5 { diff --git a/test/rplmfparser/baseTest.txt b/test/rplmfparser/baseTest.txt index 0f195b5..10ff423 100644 --- a/test/rplmfparser/baseTest.txt +++ b/test/rplmfparser/baseTest.txt @@ -1,5 +1,5 @@ 2+3*4 -= (module) parent: global += (module) parent: $global == Body: Expr id: 6 expr: 2 succ: 0 :1:1 BinOp id: 2 op: + (26) left: 1 right: 4 :1:1 diff --git a/test/rplmfparser/defTest.txt b/test/rplmfparser/defTest.txt index 89dc16b..e8826b3 100644 --- a/test/rplmfparser/defTest.txt +++ b/test/rplmfparser/defTest.txt @@ -1,5 +1,5 @@ Int i = 3; const lazy Str s = 'Hi'; const List l; -= (module) parent: global += (module) parent: $global == Variables: varDef i id: 2 namedValue: 1 value: 3 succ: 5 :1:4 namedValue i id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/field1.txt b/test/rplmfparser/field1.txt index 4cbe926..b9960df 100644 --- a/test/rplmfparser/field1.txt +++ b/test/rplmfparser/field1.txt @@ -1,7 +1,7 @@ file.find('*.c')[0].name; [1,2,3].join(' '); 3.14.trunc; -= (module) parent: global += (module) parent: $global == Body: Expr id: 8 expr: 7 succ: 15 :1:24 field name id: 7 parent: 5 succ: :1:24 diff --git a/test/rplmfparser/forC1.txt b/test/rplmfparser/forC1.txt index 64c14c3..82ef81d 100644 --- a/test/rplmfparser/forC1.txt +++ b/test/rplmfparser/forC1.txt @@ -2,7 +2,7 @@ Int a; for b from 10 to 1 step -2 do a += 1; od -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 0 succ: 4 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/forC2.txt b/test/rplmfparser/forC2.txt index 117dc32..1ad1331 100644 --- a/test/rplmfparser/forC2.txt +++ b/test/rplmfparser/forC2.txt @@ -1,5 +1,5 @@ Int a; for to 10 do a += 1 od -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 0 succ: 3 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/forIt1.txt b/test/rplmfparser/forIt1.txt index e76a69d..b3198fd 100644 --- a/test/rplmfparser/forIt1.txt +++ b/test/rplmfparser/forIt1.txt @@ -2,7 +2,7 @@ Map a; for x in a do a += 1; od -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 0 succ: 4 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/ifTest1.txt b/test/rplmfparser/ifTest1.txt index 217a7be..136e306 100644 --- a/test/rplmfparser/ifTest1.txt +++ b/test/rplmfparser/ifTest1.txt @@ -5,7 +5,7 @@ if 11 < 12 then a = 13 * 14 else a = 15 / 16 fi -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 0 succ: 4 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/ifTest2.txt b/test/rplmfparser/ifTest2.txt index bfaa9ea..26a5e66 100644 --- a/test/rplmfparser/ifTest2.txt +++ b/test/rplmfparser/ifTest2.txt @@ -2,7 +2,7 @@ Str x; if 7 < 6 then x = '123'; fi -= (module) parent: global += (module) parent: $global == Variables: varDef x id: 2 namedValue: 1 value: 0 succ: 3 :1:4 namedValue x id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/list1.txt b/test/rplmfparser/list1.txt index 2de17e1..9c0026e 100644 --- a/test/rplmfparser/list1.txt +++ b/test/rplmfparser/list1.txt @@ -1,5 +1,5 @@ List b = []; -= (module) parent: global += (module) parent: $global == Variables: varDef b id: 2 namedValue: 1 value: 3 succ: 0 :1:5 namedValue b id: 1 attr: 0x0 :1:5 diff --git a/test/rplmfparser/list2.txt b/test/rplmfparser/list2.txt index fd904e5..1f2deea 100644 --- a/test/rplmfparser/list2.txt +++ b/test/rplmfparser/list2.txt @@ -1,5 +1,5 @@ List a = [2+3, 3.14, 7, 'hi', a]; List b = []; -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 3 succ: 11 :1:5 namedValue a id: 1 attr: 0x0 :1:5 diff --git a/test/rplmfparser/map1.txt b/test/rplmfparser/map1.txt index 0d69fce..1e51ff7 100644 --- a/test/rplmfparser/map1.txt +++ b/test/rplmfparser/map1.txt @@ -1,5 +1,5 @@ Map a = {}; -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 3 succ: 0 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/map2.txt b/test/rplmfparser/map2.txt index ca85376..35c7852 100644 --- a/test/rplmfparser/map2.txt +++ b/test/rplmfparser/map2.txt @@ -1,6 +1,6 @@ Map a = {'a': 2+3,'bcd':3.14,'ccc':7, 'hi':'world'}; Map b = {}; -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 3 succ: 11 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/meth1.txt b/test/rplmfparser/meth1.txt index 3f7dc3f..ba888fc 100644 --- a/test/rplmfparser/meth1.txt +++ b/test/rplmfparser/meth1.txt @@ -1,5 +1,5 @@ func Float pi: 3.1415; endf func Str delim(): '/' endf; -= (module) parent: global += (module) parent: $global == Methods: Method delim() id: 4 parent: args: 0 body: 6 :1:28 Expr id: 6 expr: 5 succ: 0 :1:46 diff --git a/test/rplmfparser/meth2.txt b/test/rplmfparser/meth2.txt index 4838410..c29148d 100644 --- a/test/rplmfparser/meth2.txt +++ b/test/rplmfparser/meth2.txt @@ -1,7 +1,7 @@ func Int fac(const Int n): Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi rc endf -= (module) parent: global += (module) parent: $global == Methods: Method fac() id: 1 parent: args: 4 body: 6 :0:55 Expr id: 4 expr: 3 succ: 0 diff --git a/test/rplmfparser/meth3.txt b/test/rplmfparser/meth3.txt index 74b57d8..f3fe793 100644 --- a/test/rplmfparser/meth3.txt +++ b/test/rplmfparser/meth3.txt @@ -6,7 +6,7 @@ endf func Int max(const Int a, Int b, Int c): max(a, max(b, c)) endf -= (module) parent: global += (module) parent: $global == Methods: Method max() id: 21 parent: args: 24 body: 40 :5:5 Expr id: 24 expr: 23 succ: 27 diff --git a/test/rplmfparser/meth4.txt b/test/rplmfparser/meth4.txt index 1e0449a..ac39b73 100644 --- a/test/rplmfparser/meth4.txt +++ b/test/rplmfparser/meth4.txt @@ -6,7 +6,7 @@ rc endf max(a, max(b, c)) endf -= (module) parent: global += (module) parent: $global == Methods: Method max() id: 1 parent: args: 4 body: 40 :0:4 Expr id: 4 expr: 3 succ: 7 diff --git a/test/rplmfparser/methc1.txt b/test/rplmfparser/methc1.txt index 3ccf636..e418cbb 100644 --- a/test/rplmfparser/methc1.txt +++ b/test/rplmfparser/methc1.txt @@ -1,7 +1,7 @@ rand(); sin(a); max(1+2*3,4**(5-4)); -= (module) parent: global += (module) parent: $global == Body: Expr id: 2 expr: 1 succ: 6 :1:4 call rand Id: 1 args: 0 parent: 0 succ: 0 :1:4 diff --git a/test/rplmfparser/opTest1.txt b/test/rplmfparser/opTest1.txt index ac8e160..b632366 100644 --- a/test/rplmfparser/opTest1.txt +++ b/test/rplmfparser/opTest1.txt @@ -4,7 +4,7 @@ Int b = 100; b++; a--*++b**(8-3); a=b=(a+(b-2)*3) -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 3 succ: 5 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/repeatTest.txt b/test/rplmfparser/repeatTest.txt index e2acdec..1d1818e 100644 --- a/test/rplmfparser/repeatTest.txt +++ b/test/rplmfparser/repeatTest.txt @@ -2,7 +2,7 @@ Int a; repeat a++; until a != 2 * 3; -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 0 succ: 3 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/test/rplmfparser/whileTest.txt b/test/rplmfparser/whileTest.txt index ad6887d..44bccb1 100644 --- a/test/rplmfparser/whileTest.txt +++ b/test/rplmfparser/whileTest.txt @@ -2,7 +2,7 @@ Int a = 20; while 3 < 5 do a = 7 od -= (module) parent: global += (module) parent: $global == Variables: varDef a id: 2 namedValue: 1 value: 3 succ: 4 :1:4 namedValue a id: 1 attr: 0x0 :1:4 diff --git a/unittests/main.cpp b/unittests/main.cpp index 87406f8..74a7451 100644 --- a/unittests/main.cpp +++ b/unittests/main.cpp @@ -11,6 +11,8 @@ #include void testCore(){ + extern void testRplByteStorage(); + testRplByteStorage(); extern void testRplQString(); testRplQString(); diff --git a/unittests/rplbytestorage_test.cpp b/unittests/rplbytestorage_test.cpp new file mode 100644 index 0000000..6c8ae4c --- /dev/null +++ b/unittests/rplbytestorage_test.cpp @@ -0,0 +1,73 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ +#include "rplcore/rplcore.hpp" +#include "rplcore/rpltest.hpp" + +class TestRplByteStorage : public RplTest{ +public: + TestRplByteStorage() : + RplTest("RplByteStorage") + {} +private: + void testChars(){ + RplByteStorage store(100); + char* s1 = store.allocateChars(4); + memcpy((void*) s1, "123", 4); + const char* s2 = store.allocateChars("abc"); + const char* s3 = store.allocateChars("defghij", 3); + checkE(s1, "123"); + checkE(s2, "abc"); + checkE(s3, "def"); + const char* ptr = s1 + 4; + checkT(ptr == s2); + ptr += 4; + checkT(ptr == s3); + } + + void testBytes(){ + RplByteStorage store(100); + uint8_t* s1 = store.allocateBytes(4); + memcpy((void*) s1, "1234", 4); + uint8_t* s2 = store.allocateBytes((void*) "abcd", 4); + uint8_t* s3 = store.allocateBytes((void*) "efghij", 4); + uint8_t* s4 = store.allocateZeros(4); + + checkE("1234abcdefgh", (const char*) s1); + uint8_t* ptr = s1 + 4; + checkT(ptr == s2); + ptr += 4; + checkT(ptr == s3); + ptr += 4; + checkT(ptr == s4); + for (int ii = 0; ii < 4; ii++) + checkE(0, (int) s4[ii]); + } + void testBufferChange(){ + RplByteStorage store(10); + char buffer[2]; + buffer[1] = '\0'; + for (int ii = 0; ii < 10000; ii++){ + buffer[1] = 'A' + ii % 26; + store.allocateBytes(buffer, 1); + } + int a = 1; + } + +public: + virtual void doIt() { + testBufferChange(); + testChars(); + testBytes(); + } +}; +void testRplByteStorage() { + TestRplByteStorage test; + test.run(); +} + + diff --git a/unittests/unittests.pro b/unittests/unittests.pro index 891dbfd..a28f5c2 100644 --- a/unittests/unittests.pro +++ b/unittests/unittests.pro @@ -37,5 +37,8 @@ SOURCES += main.cpp \ ../rplexpr/rplasclasses.cpp \ rplastree_test.cpp \ rplmfparser_test.cpp \ - ../rplexpr/rplvm_test.cpp + ../rplexpr/rplvm_test.cpp \ + rplbytestorage_test.cpp \ + ../rplcore/rplbytestorage.cpp \ + ../rplexpr/rplvm.cpp -- 2.39.5