--- /dev/null
+/*
+ * 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 <code>new()</code>.
+ */
+
+/**
+ * @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 <code>size</code> 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<char*>(rc);
+}
+
+/**
+ * @brief Duplicates a string into a new allocated block.
+ *
+ * @param source the source string
+ * @param size the length of the string.
+ * If < 0 <code>strlen(source)</code> 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<uint8_t*>(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;
+}
--- /dev/null
+/*
+ * 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
#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"
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.
* 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.
*/
* @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){
}
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.
*
};
class RplASUserClass;
+class RplASTree;
class RplSymbolSpace
{
public:
typedef QMap<QString, RplASClass*> ClassMap;
typedef QMap<QString, RplASMethod*> MethodMap;
typedef QList<RplASVarDefinition*> VariableList;
+private:
+ RplSymbolSpace(RplASTree& tree);
public:
RplSymbolSpace(SymbolSpaceType type, const QString& name,
RplSymbolSpace* parent);
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;
RplSymbolSpace* m_parent;
RplASItem* m_body;
VariableList m_listOfVars;
-
-public:
- static RplSymbolSpace m_global;
+ RplASTree& m_tree;
};
class RplASBoolean : public RplASClass {
/** @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),
* @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;
* @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;
}
* @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();
}
*/
void RplASTree::init()
{
+ m_global = RplSymbolSpace::createGlobal(*this);
m_symbolSpaces.append(m_global);
m_currentSpace = m_global;
}
}
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.
class RplASCondition;
class RplASVariant {
+ /* The VM uses some tricks (performance): Therefore this class
+ * must not be virtual!
+ */
public:
enum VariantType {
VT_UNDEF,
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
const char* header = NULL);
RplSymbolSpace*findmodule(const QString& name);
RplSourcePosition* copyPosition();
+ RplByteStorage& store();
+
protected:
void init();
void destroy();
RplSymbolSpace* m_currentSpace;
// contain all ever built symbol spaces:
SymbolSpaceMap m_symbolSpaceHeap;
+ RplByteStorage m_store;
};
#endif // RPLASTREE_HPP
RplToken* RplLexer::nextToken()
{
RplToken* rc = NULL;
- const RplSourcePosition* waitingPosition = NULL;
int ix;
if (m_waitingToken != NULL){
rc = m_currentToken = m_waitingToken;
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())
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)){
m_variables(NULL),
m_symbols(symbols)
{
- if (m_countLocals > 0)
+ if (m_countVariables > 0)
m_variables = new RplASVariant[m_countVariables];
}
{
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"
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<RplASCalculable*>(statements);
- statement->calc(&m_currentValue);
+ statement->calc(m_currentValue);
}
}
*
* 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);
}
/**
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<RplASNode1*>(initialization),
+ spaceInitialization);
}
if (statements != NULL)
- thread->execute(statements, space);
+ thread->execute(dynamic_cast<RplASNode1*>(statements), space);
}
/**
* @brief Tests whether a given flag is set.
bool RplVirtualMachine::hasFlag(RplVirtualMachine::VMFlag flag) const
{
bool rc = (m_flags & flag) != 0;
+ return rc;
}
/**
* @brief Adds a flag to the current flags.
*/
void RplVirtualMachine::setFlag(RplVirtualMachine::VMFlag flag)
{
- m_flag |= flag;
+ m_flags |= flag;
}
/**
*/
void RplVirtualMachine::clearFlag(RplVirtualMachine::VMFlag flag)
{
- m_flag &= ~flag;
+ m_flags &= ~flag;
}
VF_TRACE_AUTO_VARIABLES = 1<<3
};
-
+ typedef QList<const char*> LineList;
public:
RplVirtualMachine(RplASTree& tree, RplSource& source, int maxStack = 1024);
public:
int m_flags;
RplSource& m_source;
RplASTree& m_tree;
+ LineList m_trace;
};
#endif // RPLVM_HPP
fnExpected += (char) QDir::separator().toLatin1();
fnExpected += fileExpected;
QByteArray fnCurrent = getTempFile(fileExpected, "rplvm");
+ vm.setFlag(RplVirtualMachine::VF_TRACE_STATEMENTS);
vm.executeModule("<test>");
- vm.dump(fnCurrent, RplASTree::DMP_NO_GLOBALS);
+ //vm.dump(fnCurrent, RplASTree::DMP_NO_GLOBALS);
assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
__FILE__, lineNo);
}
../rplexpr/rplasclasses.cpp \
../rplexpr/rplmfparser.cpp \
../rplexpr/rplvm.cpp \
- ../rplexpr/rplparser.cpp
+ ../rplexpr/rplparser.cpp \
+ ../rplcore/rplbytestorage.cpp
HEADERS += ../rplmodules.hpp \
../rplcore/rplconfig.hpp \
../rplexpr/rplasclasses.hpp \
../rplexpr/rplmfparser.hpp \
../rplexpr/rplvm.hpp \
- ../rplexpr/rplparser.hpp
+ ../rplexpr/rplparser.hpp \
+ ../rplcore/rplbytestorage.hpp
unix:!symbian {
maemo5 {
2+3*4
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Body:
Expr id: 6 expr: 2 succ: 0 <test>:1:1
BinOp id: 2 op: + (26) left: 1 right: 4 <test>:1:1
Int i = 3; const lazy Str s = 'Hi'; const List l;
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef i id: 2 namedValue: 1 value: 3 succ: 5 <test>:1:4
namedValue i id: 1 attr: 0x0 <test>:1:4
file.find('*.c')[0].name;
[1,2,3].join(' ');
3.14.trunc;
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Body:
Expr id: 8 expr: 7 succ: 15 <test>:1:24
field name id: 7 parent: 5 succ: <test>:1:24
for b from 10 to 1 step -2 do
a += 1;
od
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 0 succ: 4 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
Int a; for to 10 do a += 1 od
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 0 succ: 3 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
for x in a do
a += 1;
od
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 0 succ: 4 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
then a = 13 * 14
else a = 15 / 16
fi
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 0 succ: 4 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
if 7 < 6
then x = '123';
fi
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef x id: 2 namedValue: 1 value: 0 succ: 3 <test>:1:4
namedValue x id: 1 attr: 0x0 <test>:1:4
List b = [];
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef b id: 2 namedValue: 1 value: 3 succ: 0 <test>:1:5
namedValue b id: 1 attr: 0x0 <test>:1:5
List a = [2+3, 3.14, 7, 'hi', a]; List b = [];
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 3 succ: 11 <test>:1:5
namedValue a id: 1 attr: 0x0 <test>:1:5
Map a = {};
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 3 succ: 0 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
Map a = {'a': 2+3,'bcd':3.14,'ccc':7, 'hi':'world'};
Map b = {};
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 3 succ: 11 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
func Float pi: 3.1415; endf func Str delim(): '/' endf;
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Methods:
Method <NoneType> delim() id: 4 parent: <test> args: 0 body: 6 <test>:1:28
Expr id: 6 expr: 5 succ: 0 <test>:1:46
func Int fac(const Int n):
Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi
rc endf
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Methods:
Method <NoneType> fac() id: 1 parent: <test> args: 4 body: 6 <test>:0:55
Expr id: 4 expr: 3 succ: 0
func Int max(const Int a, Int b, Int c):
max(a, max(b, c))
endf
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Methods:
Method <NoneType> max() id: 21 parent: <test> args: 24 body: 40 <test>:5:5
Expr id: 24 expr: 23 succ: 27
endf
max(a, max(b, c))
endf
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Methods:
Method <NoneType> max() id: 1 parent: <test> args: 4 body: 40 <test>:0:4
Expr id: 4 expr: 3 succ: 7
rand();
sin(a);
max(1+2*3,4**(5-4));
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Body:
Expr id: 2 expr: 1 succ: 6 <test>:1:4
call rand Id: 1 args: 0 parent: 0 succ: 0 <test>:1:4
b++;
a--*++b**(8-3);
a=b=(a+(b-2)*3)
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 3 succ: 5 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
repeat
a++;
until a != 2 * 3;
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 0 succ: 3 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
while 3 < 5 do
a = 7
od
-= <test> (module) parent: global
+= <test> (module) parent: $global
== Variables:
varDef a id: 2 namedValue: 1 value: 3 succ: 4 <test>:1:4
namedValue a id: 1 attr: 0x0 <test>:1:4
#include <QCoreApplication>
void testCore(){
+ extern void testRplByteStorage();
+ testRplByteStorage();
extern void testRplQString();
testRplQString();
--- /dev/null
+/*
+ * 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();
+}
+
+
../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