]> gitweb.hamatoma.de Git - reqt/commitdiff
dayly work
authorhama <hama@siduction.net>
Tue, 24 Jun 2014 22:26:35 +0000 (00:26 +0200)
committerhama <hama@siduction.net>
Tue, 24 Jun 2014 22:26:35 +0000 (00:26 +0200)
24 files changed:
rplcore/rplconfig.hpp
rplcore/rpllogger.cpp
rplcore/rpllogger.hpp
rplcore/rplstring.cpp
rplcore/rplstring.hpp
rplcore/rpltest.cpp
rplcore/rpltest.hpp
rplexpr/rplasclasses.cpp
rplexpr/rplasclasses.hpp
rplexpr/rplastree.cpp
rplexpr/rplastree.hpp
rplexpr/rplexpr.hpp
rplexpr/rpllexer.cpp
rplexpr/rpllexer.hpp
rplexpr/rplmfparser.cpp [new file with mode: 0644]
rplexpr/rplmfparser.hpp [new file with mode: 0644]
rplexpr/rplsource.cpp
rplexpr/rplvm.cpp [new file with mode: 0644]
rplexpr/rplvm.hpp [new file with mode: 0644]
rplstatic/rplstatic.pro
unittests/main.cpp
unittests/rplastree_test.cpp [new file with mode: 0644]
unittests/rplstring_test.cpp
unittests/unittests.pro

index 46af10682a258e6737dcb9b2ed4b1c79d5a0a233..abf3a71fdd2064de4ea4531460c5684ec140ad38 100644 (file)
@@ -18,7 +18,7 @@ public:
     bool read(const char* file);
     bool write(const char* file);
     void clear();
-    const QVector<QByteArray>& getLines() const;
+    const QList<QByteArray>& getLines() const;
 
     virtual bool asBool(const char* key, bool defaultValue) const;
     virtual int asInt(const char* key, int defaultValue) const;
@@ -27,7 +27,7 @@ private:
     void initLogger();
 private:
     const char* m_file;
-    QVector<QByteArray> m_lineList;
+    QList<QByteArray> m_lineList;
     bool m_readOnly;
     RplLogger* m_logger;
     // true: the logger must be destroyed in the destructor
index e044b9736c2104677341910578346e68de41f428..0499c1a93ad45b325fee5460b3e476833c2235d4 100644 (file)
@@ -624,7 +624,7 @@ void RplMemoryAppender::log(RplLoggerLevel level, int location,
  *
  * @return the line list
  */
-const QVector<QByteArray>& RplMemoryAppender::getLines() const {
+const QList<QByteArray>& RplMemoryAppender::getLines() const {
     return m_lines;
 }
 
index 37e56ebb508c161e85ae7db9bd61844202d10ec9..791d14cd93ca97f80259d2599f50cdfe701fb69d 100644 (file)
@@ -155,10 +155,10 @@ public:
 public:
     virtual void log(RplLoggerLevel level, int location, const char* message,
                      RplLogger* logger);
-    const QVector<QByteArray>& getLines() const;
+    const QList<QByteArray>& getLines() const;
     void clear();
 private:
-    QVector<QByteArray> m_lines;
+    QList<QByteArray> m_lines;
     // maximum count of m_lines. If larger the oldest lines will be deleted.
     int m_maxLines;
     // true: standard prefix (level + datetime) will be stored too.
index 6a2b3e7b4e59cecd7e79a414eed7ae5b3963ea86..da2c2c9b6ab7d61abaa946868f1726cfa3c6063c 100644 (file)
@@ -208,10 +208,10 @@ QByteArray RplString::replaceNode(const char* source, const char* newNode){
  * @param separator     the separator between the items to split
  * @return              an array with the splitted source
  */
-QVector<QByteArray> RplString::toArray(const char* source,
+QList<QByteArray> RplString::toArray(const char* source,
                                        const char* separator) {
     const char* end = source;
-    QVector<QByteArray> rc;
+    QList<QByteArray> rc;
     rc.reserve(count(source, separator) + 1);
     int lengthItem = strlen(separator);
     while(*end != '\0') {
index d287ff02d402275a7bd1a44dbdfcda235decb7fc..ab12169de3b1ac86a23eccbd7c172b83ab36b635 100644 (file)
@@ -24,7 +24,7 @@ public:
     static QByteArray replaceNode(const char* source, const char* newNode);
     static bool write(const char* file, const char* content = NULL,
                       const char* mode = "w");
-    static QVector<QByteArray> toArray(const char* source, const char* separator);
+    static QList<QByteArray> toArray(const char* source, const char* separator);
     static QByteArray toCString(const char* source, int maxLength = -1);
     static QByteArray toNumber(int value, const char* format = "%d");
     static int lengthOfNumber(const char* text, bool skipTrailingSpaces = false);
index 7cce846311382f295afdde441a77f3152225ba8b..abb952fe350f685ab0dfa0286e4abae0765536be 100644 (file)
@@ -172,8 +172,8 @@ bool RplTest::assertEquals(const char* expected, const char* current,
     bool equal = strcmp(expected, current) == 0;
     if(! equal) {
         if(strchr(expected, '\n') != NULL || strchr(current, '\n')) {
-            QVector<QByteArray> exp = RplString::toArray(expected, "\n");
-            QVector<QByteArray> cur = RplString::toArray(current, "\n");
+            QList<QByteArray> exp = RplString::toArray(expected, "\n");
+            QList<QByteArray> cur = RplString::toArray(current, "\n");
             equal = assertEquals(exp, cur, file, lineNo);
         } else {
             int ix = 0;
@@ -211,8 +211,8 @@ bool RplTest::assertEquals(const char* expected, const char* current,
  * @param lineNo        the line number containing the test
  * @return              true: equal
  */
-bool RplTest::assertEquals(const QVector<QByteArray>& expected,
-                           const QVector<QByteArray>& current, const char* file, int lineNo) {
+bool RplTest::assertEquals(const QList<QByteArray>& expected,
+                           const QList<QByteArray>& current, const char* file, int lineNo) {
     int nMax = expected.size();
     bool rc = true;
     if(current.size() < nMax)
@@ -370,7 +370,7 @@ bool RplTest::error(const char* format, ...) {
  */
 bool RplTest::logContains(const char* pattern)
 {
-    const QVector<QByteArray>& lines = m_memoryAppender.getLines();
+    const QList<QByteArray>& lines = m_memoryAppender.getLines();
     QRegularExpression rexpr(pattern);
     bool rc = false;
     QRegularExpressionMatch match;
index e5cbde52d701fccd650bba509d8fb90afdbe1829..ed7caed8551eee9dc59c46411f495a902f22d037 100644 (file)
@@ -36,8 +36,8 @@ public:
                       const char* file, int lineNo);
     bool assertEquals(const char* expected, const QByteArray& current,
                       const char* file, int lineNo);
-    bool assertEquals(const QVector<QByteArray>& expected,
-                      const QVector<QByteArray>& current, const char* file, int lineNo);
+    bool assertEquals(const QList<QByteArray>& expected,
+                      const QList<QByteArray>& current, const char* file, int lineNo);
     bool assertTrue(bool condition, const char* file, int lineNo);
     bool assertFalse(bool condition, const char* file, int lineNo);
     bool assertNull(const void* ptr, const char* file, int lineNo);
index f37101d927a40a138112a18325ea53681fcda893..4887b5a98ff3174fc5d4e1a59931941dda1a5bc1 100644 (file)
 #include "rplcore/rplcore.hpp"
 #include "rplexpr/rplexpr.hpp"
 
-/** @class RplASList rplastree.hpp "rplexpr/rplastree.hpp"
+RplASList RplASList::m_instance;
+RplASMap RplASMap::m_instance;
+RplASFloat RplASFloat::m_instance;
+RplASInteger RplASInteger::m_instance;
+RplASString RplASString::m_instance;
+RplASBoolean RplASBoolean::m_instance;
+
+/** @class RplSymbolSpace rplastree.hpp "rplexpr/rplastree.hpp"
  *
- * @brief Implements the class of a list.
+ * @brief Implements a symbol space for the parser.
  *
- * A list is a container of any values.  Values can be selected by the index.
+ * A symbol space is a container of the classes and variables which can be used
+ * at a given moment while compiling.
+ *
+ * A symbol space could have a parent which is a symbol space too and extends
+ * the visible classes / variables.
+ *
+ * If an entry exists more than one time in a symbol space chain only the first
+ * can be seen.
+ *
+ * The "last" parent is named "global" and exists always. It contains the
+ * core classes like String, List and Map and methods like print.
+ *
+ * Each module hit by the compiler builds its own symbol space with global as parent.
+ *
+ * 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.
  */
+
 /**
  * @brief Constructor.
+ *
+ * @param name      the symbol space's name
+ * @param parent    the parent of the symbol space
  */
-RplASList::RplASList() :
-    RplASClass("List")
+RplSymbolSpace::RplSymbolSpace(RplSymbolSpace::SymbolSpaceType type,
+        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()] = &RplASBoolean::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;
+    }
+
 }
 
+/**
+ * @brief Destructor.
+ */
+RplSymbolSpace::~RplSymbolSpace()
+{
+    QMap<QString, RplVariable*>::iterator it;
+    for (it = m_variables.begin(); it != m_variables.end(); it++){
+        delete it.value();
+    }
+    for (it = m_variables.begin(); it != m_variables.end(); it++){
+        delete it.value();
+    }
+}
+/**
+ * @brief Returns the name of the symbol space.
+ *
+ * @return the name
+ */
+QString RplSymbolSpace::name() const
+{
+    return m_name;
+}
+
+
+/** @class RplASBoolean rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is a real value.
+ */
+/**
+ * @brief Constructor.
+ */
+RplASBoolean::RplASBoolean() :
+    RplASClass("Boolean")
+{
+}
 /**
  * @brief Creates a value object (used in RplASVariant).
  *
+ * For Booleans nothing is to do!
+ *
  * @param source    NULL or a source to copy
- * @return          a new value object (specific for the class)
+ * @return          NULL
  */
-void* RplASList::newValueInstance(void* source)
+void* RplASBoolean::newValueInstance(void* source) const
 {
-    QList<RplASVariant*>* rc = new QList<RplASVariant*>();
-    if (source != NULL){
-        QList* source2 = (QList*) source;
-        rc->reserve(source2->size());
-        QList<RplASVariant*>::iterator it;
-        for (it = source->begin();
-                it != source->end();
-                it++){
-            // deleting in destroyValue():
-            rc->append(new RplASValue(*it));
-        }
-    }
-    return (void*) rc;
+    return NULL;
 }
 
 /**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
  *
- * The object must be created by <code>newValueInstance()</code>.
+ * For Booleans nothing is to do!
  *
  * @param object    object to destroy
  */
-void RplASList::destroyValueInstance(void* object)
+void RplASBoolean::destroyValueInstance(void* object) const
 {
-    delete (QList*) object;
 }
 
-/** @class RplASMap rplastree.hpp "rplexpr/rplastree.hpp"
+/**
+ * @brief Calculates the boolean value of an class specific object.
  *
- * @brief Implements the class of a map.
+ * This method should never be called.
  *
- * A map is a container of (key, value) pairs.
- * Values can be selected by the key.
+ * @param object    the object to test (with type QList*)
+ * @return          false
+ */
+bool RplASBoolean::boolValueOf(void* object) const
+{
+    return false;
+}
+
+/** @class RplASNumber rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is a one of the values true and false.
  */
 /**
  * @brief Constructor.
  */
-RplASMap::RplASMap() :
-    RplASClass("Map")
+RplASFloat::RplASFloat() :
+    RplASClass("Boolean")
 {
 }
+
+RplASFloat::RplASFloat(const QString& name) :
+    RplASClass(name)
+{
+    m_superClass = &RplASFloat::m_instance;
+}
 /**
  * @brief Creates a value object (used in RplASVariant).
  *
+ * For Booleans nothing is to do!
+ *
  * @param source    NULL or a source to copy
- * @return          a new value object (specific for the class)
+ * @return          NULL
  */
-void* RplASMap::newValueInstance(void* source)
+void* RplASFloat::newValueInstance(void* source) const
 {
-    QMap<QString, RplASVariant*>* rc = new QMap<QString, RplASVariant*>();
-    if (source != NULL){
-        QMap<QString, RplASVariant*>* source2 =
-                (QMap<QString, RplASVariant*>*) source;
-        rc->reserve(source2->size());
-        QMap<QString, RplASVariant*>::iterator it;
-        for (it = source->begin();
-                it != source->end();
-                it++){
-            // deleting in destroyValue():
-            rc->append(new RplASValue(*it));
-        }
-    }
-    return (void*) rc;
+    return NULL;
 }
 
 /**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
  *
- * The object must be created by <code>newValueInstance()</code>.
+ * For Booleans nothing is to do!
  *
  * @param object    object to destroy
  */
-void RplASMap::destroyValueInstance(void* object)
+void RplASFloat::destroyValueInstance(void* object) const
+{
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object    the object to test
+ * @return          false
+ */
+bool RplASFloat::boolValueOf(void* object) const
 {
-    delete (QMap<QString, RplASVariant*>*) object;
+    return false;
 }
 
+/** @class RplASInteger rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is a one of the values true and false.
+ */
+/**
+ * @brief Constructor.
+ */
+RplASInteger::RplASInteger() :
+    RplASFloat("Integer")
+{
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object    the object to test
+ * @return          false
+ */
+bool RplASInteger::boolValueOf(void* object) const
+{
+    return false;
+}
+
+
+
 /** @class RplASString rplastree.hpp "rplexpr/rplastree.hpp"
  *
  * @brief Implements the class of a string.
@@ -128,56 +246,179 @@ RplASString::RplASString() :
  * @param source    NULL or a source to copy
  * @return          a new value object (specific for the class)
  */
-void* RplASString::newValueInstance(void* source)
+void* RplASString::newValueInstance(void* source) const
 {
     QString* rc = source == NULL ? new QString() : new QString(*(QString*) source);
     return (void*) rc;
 }
 
 /**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
  *
  * The object must be created by <code>newValueInstance()</code>.
  *
  * @param object    object to destroy
  */
-void RplASString::destroyValueInstance(void* object)
+void RplASString::destroyValueInstance(void* object) const
 {
     delete (QString*) object;
 }
 
-/** @class RplASNumber rplastree.hpp "rplexpr/rplastree.hpp"
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object    the object to test (a QString* instance)
+ * @return          false: the string is empty
+ *                  true: otherwise
+ */
+bool RplASString::boolValueOf(void* object) const
+{
+    bool rc = false;
+    if (object != NULL){
+        QString* string = static_cast<QString*>(object);
+        if (string == NULL)
+            throw RplException("RplASString.boolValueOf(): not a string");
+        rc = ! string->isEmpty();
+    }
+    return rc;
+}
+
+
+/** @class RplASList rplastree.hpp "rplexpr/rplastree.hpp"
  *
- * @brief Implements the class of a Number.
+ * @brief Implements the class of a list.
  *
- * A Number is a real value.
+ * A list is a container of any values.  Values can be selected by the index.
  */
 /**
  * @brief Constructor.
  */
-RplASNumber::RplASNumber() :
-    RplASClass("Number")
+RplASList::RplASList() :
+    RplASClass("List")
 {
 }
+
 /**
  * @brief Creates a value object (used in RplASVariant).
  *
  * @param source    NULL or a source to copy
- * @return          NULL
+ * @return          a new value object (specific for the class)
+ */
+void* RplASList::newValueInstance(void* source) const
+{
+    ListValueType* rc = new ListValueType();
+    if (source != NULL){
+        ListValueType* source2 = (ListValueType*) source;
+        rc->reserve(source2->size());
+        ListValueType::iterator it;
+        for (it = source2->begin();
+                it != source2->end();
+                it++){
+            // deleting in destroyValue():
+            rc->append(new RplASVariant(*(*it)));
+        }
+    }
+    return (void*) rc;
+}
+
+/**
+ * @brief Destroys the given object.
+ *
+ * The object must be created by <code>newValueInstance()</code>.
+ *
+ * @param object    object to destroy
+ */
+void RplASList::destroyValueInstance(void* object) const
+{
+    delete static_cast<ListValueType*>(object);
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * @param object    the object to test (with type QList*)
+ * @return          false: the list is empty<br>
+ *                  true: otherwise
+ */
+bool RplASList::boolValueOf(void* object) const
+{
+    bool rc = false;
+    if (object != NULL){
+        ListValueType* list = static_cast<ListValueType*>(object);
+        if (list == NULL)
+            throw RplException("RplASList.boolValueOf(): not a list");
+        rc = ! list->empty();
+    }
+    return rc;
+}
+
+/** @class RplASMap rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a map.
+ *
+ * A map is a container of (key, value) pairs.
+ * Values can be selected by the key.
+ */
+/**
+ * @brief Constructor.
  */
-void* RplASNumber::newValueInstance(void* source)
+RplASMap::RplASMap() :
+    RplASClass("Map")
 {
-    return null;
+}
+/**
+ * @brief Creates a value object (used in RplASVariant).
+ *
+ * @param source    NULL or a source to copy
+ * @return          a new value object (specific for the class)
+ */
+void* RplASMap::newValueInstance(void* source) const
+{
+    MapValueType* rc = new MapValueType();
+    if (source != NULL){
+        MapValueType* source2 =
+                static_cast<MapValueType*>(source);
+        // rc->reserve(source2->size());
+        MapValueType::iterator it;
+        for (it = source2->begin(); it != source2->end(); it++){
+            // deleting in destroyValue():
+            const QString& key = it.key();
+            RplASVariant* value = new RplASVariant(*it.value());
+            (*rc)[key] = value;
+        }
+    }
+    return (void*) rc;
 }
 
 /**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
  *
  * The object must be created by <code>newValueInstance()</code>.
  *
  * @param object    object to destroy
  */
-void RplASNumber::destroyValueInstance(void* object)
+void RplASMap::destroyValueInstance(void* object) const
 {
+    delete (MapValueType*) object;
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * @param object    the object to test (with type QMap*)
+ * @return
+ */
+bool RplASMap::boolValueOf(void* object) const
+{
+    bool rc = false;
+    if (object != NULL){
+        MapValueType* map = reinterpret_cast<MapValueType*>(object);
+        if (map == NULL)
+            throw RplException("RplASMap.boolValueOf(): not a map");
+        rc = map->empty() > 0;
+    }
+    return rc;
 }
 
index c456b5ed29b4449960f67fb874ae95dfa3643951..b79a51b9dedec58fd990e37cdd0e52a7213d1bf7 100644 (file)
 #ifndef RPLASCLASSES_HPP
 #define RPLASCLASSES_HPP
 
-class RplASList : public RplASClass {
+class RplSymbolSpace;
+class RplVariable {
 public:
-    RplASList();
-    ~RplASList();
+    RplVariable();
+protected:
+    QString m_name;
+    // NULL for "simple" variables (int, float, bool)
+    RplSymbolSpace* m_namespace;
+    RplASVariant m_value;
+    RplASClass* m_class;
+};
+
+class RplSymbolSpace
+{
+public:
+    enum SymbolSpaceType {
+        SST_UNDEF,
+        SST_GLOBAL,
+        SST_MODULE,
+        SST_CLASS,
+        SST_METHOD
+    };
+
+public:
+    typedef QMap<QString, RplVariable*> VariableMap;
+    typedef QMap<QString, RplASClass*> ClassMap;
+public:
+    RplSymbolSpace(SymbolSpaceType type, const QString& name,
+                   RplSymbolSpace* parent);
+    ~RplSymbolSpace();
+public:
+    RplVariable* findVariable(const QString& name) const;
+    RplASClass* findClass(const QString& name) const;
+public:
+    static void initGlobal(RplSymbolSpace& global);
+private:
+    SymbolSpaceType m_type;
+    QString m_name;
+    VariableMap m_variables;
+    ClassMap m_classes;
+    RplSymbolSpace* m_parent;
+    RplASItem* m_body;
 public:
-    void* newValueInstance(void* source = NULL);
-    void destroyValueInstance(void* object);
+    static RplSymbolSpace m_global;
+    QString name() const;
 };
 
-class RplASMap : public RplASClass {
+class RplASBoolean : public RplASClass {
 public:
-    RplASMap();
-    ~RplASMap();
+    RplASBoolean();
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
 public:
-    void* newValueInstance(void* source = NULL);
-    void destroyValueInstance(void* object);
+    static RplASBoolean m_instance;
 };
 
-class RplASNumber : public RplASClass {
+class RplASFloat : public RplASClass {
+public:
+    RplASFloat();
+    RplASFloat(const QString& name);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+public:
+    static RplASFloat m_instance;
+};
+
+class RplASInteger : public RplASFloat {
+public:
+    RplASInteger();
 public:
-    RplASNumber();
-    ~RplASNumber();
+    virtual bool boolValueOf(void* object) const;
 public:
-    void* newValueInstance(void* source = NULL);
-    void destroyValueInstance(void* object);
+    static RplASInteger m_instance;
 };
 
 class RplASString : public RplASClass {
 public:
     RplASString();
-    ~RplASString();
 public:
-    void* newValueInstance(void* source = NULL);
-    void destroyValueInstance(void* object);
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+public:
+    static RplASString m_instance;
+};
+
+class RplASList : public RplASClass {
+public:
+    typedef QList<RplASVariant*> ListValueType;
+public:
+    RplASList();
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+public:
+    static RplASList m_instance;
 };
 
+class RplASMap : public RplASClass {
+public:
+    typedef QMap<QString, RplASVariant*> MapValueType;
+public:
+    RplASMap();
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+public:
+    static RplASMap m_instance;
+};
+
+
+
 #endif // RPLASCLASSES_HPP
index 9edb1944d60a8b0079cf0a72b5b41405fad89337..3519946db3a6e68b0053f5a6019f58644e71f6a8 100644 (file)
@@ -9,6 +9,37 @@
 #include "rplcore/rplcore.hpp"
 #include "rplexpr/rplexpr.hpp"
 
+/** @class RplASException rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a specific exception for the Abstract Syntax Tree.
+ */
+
+/**
+ * @brief RplASException::RplASException
+ * @param message
+ */
+/**
+ * @brief Constructor.
+ *
+ * @param position  describes the position of the error/warning
+ * @param format    the reason of the exception
+ * @param ...       the values for the placeholders in the format.
+ */
+RplASException::RplASException(const RplSourcePosition* position,
+                                 const char* format, ...) :
+    RplException("")
+{
+    char buffer[64000];
+    if (position != NULL)
+        m_message = position->toString().toUtf8();
+    va_list ap;
+    va_start(ap, format);
+    vsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    m_message += buffer;
+}
+
+
 /** @class RplASVariant rplastree.hpp "rplexpr/rplastree.hpp"
  *
  * @brief Implements a class which can be one of the basic types.
@@ -38,6 +69,22 @@ RplASVariant::RplASVariant(const RplASVariant& source):
     // m_value
     m_class(source.m_class)
 {
+    copyValue(source);
+}
+
+/**
+ * @brief Assignment operator.
+ *
+ * @param source    the source to copy
+ * @return          the instance itself
+ */
+RplASVariant&RplASVariant::operator=(const RplASVariant& source)
+{
+    destroyValue();
+    m_dataType = source.m_dataType;
+    m_class = source.m_class;
+    copyValue(source);
+    return *this;
 }
 
 /**
@@ -48,36 +95,19 @@ void RplASVariant::copyValue(const RplASVariant& source)
 {
     switch(source.m_dataType)
     {
-    case DT_NUMBER:
-        m_value.m_number = source.m_value.m_number;
+    case DT_BOOL:
+        m_value.m_bool = source.m_value.m_bool;
         break;
-    case DT_STRING:
-        // deleting in destroyValue():
-        m_value.m_string = new QString(source.m_value.m_string);
+    case DT_FLOAT:
+        m_value.m_float = source.m_value.m_float;
         break;
-    case DT_LIST:
-    {
+    case DT_INTEGER:
+        m_value.m_int = source.m_value.m_int;
         break;
-    }
-    case DT_MAP:
-    {
-        m_value.m_map = new QList<RplASVariant*>();
-        m_value.m_map.reserve(source.m_value.m_list.size());
-        QList<RplASVariant*>::iterator it;
-        for (it = source.m_value.m_list.begin();
-                it != source.m_value.m_list.end();
-                it++){
-            // deleting in destroyValue():
-            m_value.m_list.append(new RplASValue(*it));
-        }
-        break
-    }
-    case DT_OBJECT:
-        // deleting in destroyValue():
-        m_value.m_object = m_class->newValueInstance(source.m_value.m_object);
+    case DT_UNDEF:
         break;
     default:
-        break;
+        m_value.m_object = m_class->newValueInstance(source.m_value.m_object);
     }
 }
 
@@ -86,32 +116,164 @@ void RplASVariant::copyValue(const RplASVariant& source)
  */
 void RplASVariant::destroyValue()
 {
-    switch(source.m_dataType)
+    switch(m_dataType)
     {
-    case DT_NUMBER:
-        break;
-    case DT_STRING:
-        // deleting in destroyValue():
-        m_value.m_string = delete m_value.m_string;
-        m_value.m_string = NULL;
-        break;
-    case DT_LIST:
-        delete m_value.m_list;
-        m_value.m_list = NULL;
-        break;
-    case DT_MAP:
-        delete m_value.m_map;
-        m_value.m_map = NULL;
-        break;
-    case DT_OBJECT:
-        m_map.destroyValueInstance(m_value.m_object);
-        m_value.m_object = NULL;
+    case DT_BOOL:
+    case DT_FLOAT:
+    case DT_INTEGER:
+    case DT_UNDEF:
         break;
     default:
+        m_class->destroyValueInstance(m_value.m_object);
+        m_value.m_object = NULL;
         break;
     }
 }
 
+/**
+ * @brief Returns the numeric value.
+ *
+ * @return              the numeric value
+ * @throw RplException  the instance is not a numberic value
+ *
+ */
+qreal RplASVariant::asFloat() const
+{
+    if (m_dataType != DT_FLOAT)
+        throw RplException("RplASVariant::asNumber: not a number: %d",
+                           m_dataType);
+    return m_value.m_float;
+}
+/**
+ * @brief Returns the numeric value.
+ *
+ * @return              the numeric value
+ * @throw RplException  the instance is not a numberic value
+ *
+ */
+int RplASVariant::asInt() const
+{
+    if (m_dataType != DT_INTEGER)
+        throw RplException("RplASVariant::asInt: not an integer: %d",
+                           m_dataType);
+    return m_value.m_int;
+}
+
+/**
+ * @brief Returns the boolean value.
+ *
+ * @return              the boolean value
+ * @throw RplException  the instance is not a boolean value
+ *
+ */
+bool RplASVariant::asBool() const
+{
+    if (m_dataType != DT_BOOL)
+        throw RplException("RplASVariant::asBool: not a boolean: %d",
+                           m_dataType);
+    return m_value.m_bool;
+}
+
+/**
+ * @brief Returns the class specific value.
+ *
+ * @param clazz         OUT: the class of the instance. May be NULL
+ * @return              the class specific value
+ * @throw RplException  the instance is not a boolean value
+ *
+ */
+void* RplASVariant::asObject(const RplASClass** clazz) const
+{
+    if (m_dataType != DT_OBJECT)
+        throw RplException("RplASVariant::asObject: not an object: %d",
+                           m_dataType);
+    if (clazz != NULL)
+        *clazz = m_class;
+    return m_value.m_object;
+}
+
+/**
+ * @brief Returns the value as string.
+ *
+ * @return the value as string
+ * @throw RplException  the instance is not a string value
+ */
+const QString* RplASVariant::asString() const
+{
+    const RplASClass* clazz;
+    const QString* rc = static_cast<const QString*>(asObject(&clazz));
+    if (clazz->name() != "String"){
+        const QString& name = clazz->name();
+        throw RplException("RplASVariant::asString: not an string: %s",
+                           name.toUtf8().constData());
+    }
+    return rc;
+}
+
+/**
+ * @brief Make the instance to a numeric value.
+ *
+ * @param number    the numeric value.
+ */
+void RplASVariant::setFloat(qreal number)
+{
+    destroyValue();
+    m_dataType = DT_FLOAT;
+    m_value.m_float = number;
+    m_class = &RplASFloat::m_instance;
+}
+
+/**
+ * @brief Make the instance to an integer value.
+ *
+ * @param integer    the numeric value.
+ */
+void RplASVariant::setInt(int integer)
+{
+    destroyValue();
+    m_dataType = DT_INTEGER;
+    m_value.m_int = integer;
+    m_class = &RplASInteger::m_instance;
+}
+
+/**
+ * @brief Make the instance to a boolean value.
+ *
+ * @param value    the boolean value.
+ */
+void RplASVariant::setBool(bool value)
+{
+    destroyValue();
+    m_dataType = DT_BOOL;
+    m_value.m_bool = value;
+    m_class = &RplASBoolean::m_instance;
+}
+
+/**
+ * @brief Make the instance to a boolean value.
+ *
+ * @param value    the string value.
+ */
+void RplASVariant::setString(const QString& string)
+{
+    // deletion in RplASVariant::destroyValue():
+    setObject(new QString(string), &RplASString::m_instance);
+}
+
+/**
+ * @brief Make the instance to an object.
+ *
+ * @param object    the class specific value object.
+ */
+void RplASVariant::setObject(void* object, const RplASClass* clazz)
+{
+    destroyValue();
+    m_dataType = DT_OBJECT;
+    m_value.m_object = object;
+    m_class = clazz;
+}
+
+
 /** @class RplASItem rplastree.hpp "rplexpr/rplastree.hpp"
  *
  * @brief Implements the abstract base class of all entries of an AST.
@@ -137,12 +299,22 @@ RplASItem::~RplASItem()
 {
 }
 
-RplSourcePosition* RplASItem::position() const
+/**
+ * @brief Returns the position of the item in the source code.
+ *
+ * @return the position of the item
+ */
+const RplSourcePosition* RplASItem::position() const
 {
     return m_position;
 }
 
-void RplASItem::setPosition(RplSourcePosition* position)
+/**
+ * @brief Stores the position in the source code.
+ *
+ * @param position  the position to store
+ */
+void RplASItem::setPosition(const RplSourcePosition* position)
 {
     m_position = position;
 }
@@ -152,66 +324,86 @@ void RplASItem::setPosition(RplSourcePosition* position)
  * @brief Implements the abstract base class of value containing items.
  *
  */
-RplASExpr::RplASExpr()
+RplASCalculable::RplASCalculable()
 {
 }
 
-/** @class RplASValue rplastree.hpp "rplexpr/rplastree.hpp"
+/** @class RplASConstant rplastree.hpp "rplexpr/rplastree.hpp"
  *
- * @brief Implements the abstract base class of all named values, e.g. variables.
+ * @brief Implements a constant for the Abstract Syntax Tree.
  *
  */
 
 /**
  * @brief Constructor.
  *
- * @param type      the type of the instance
- * @param name      the name of the instance
- * @param isConst   true: the value is constant: It is not allowed to change it
  */
-RplASValue::RplASValue(RplASItemType type, const QString& name, boolean isConst) :
-    RplASItem(type),
-    m_name(name),
-    m_isConst(isConst)
+RplASConstant::RplASConstant() :
+    RplASItem(AST_CONSTANT),
+    m_value()
 {
 }
+
 /**
- * @brief Destructor.
+ * @brief Calculates the expression.
+ *
+ * @param value     OUT: the calculated value
  */
-RplASValue::~RplASValue()
+void RplASConstant::calc(RplASVariant& value)
 {
+    value = m_value;
 }
 
+/**
+ * @brief Returns the value of the constant.
+ *
+ * This method will be used to set the value of the constant:
+ * <pre><code>RplASConstant constant;
+ * constant.value().setString("Jonny");
+ *</code></pre>
+ *
+ * @return the internal value
+ */
+RplASVariant& RplASConstant::value()
+{
+    return m_value;
+}
 
-/** @class RplASScalar rplastree.hpp "rplexpr/rplastree.hpp"
+/** @class RplASNamedValue rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the abstract base class of all named values, e.g. variables.
  *
- * @brief Implements a variable/constant with exactly one value.
  */
+
 /**
- * @brief Constructor
- * @param name
- * @param isConst
+ * @brief Constructor.
+ *
+ * @param name      the name of the instance
+ * @param attr      a bitmask of <code>Attribute</code> values, e.g. A_CONST
  */
-RplASScalar::RplASScalar(const QString& name, boolean isConst) :
-    RplASValue(AST_SCALAR, name, isConst),
-    m_value()
+RplASNamedValue::RplASNamedValue(const QString& name, int attributes) :
+    RplASItem(AST_NAMED_VALUE),
+    m_name(name),
+    m_attributes(attributes)
 {
 }
-
 /**
- * @brief Destructor.
+ * @brief Returns the name.
+ *
+ * @return the name
  */
-RplASScalar::~RplASScalar()
+QString RplASNamedValue::name() const
 {
+    return m_name;
 }
-
 /**
- * @brief RplASScalar::calc
- * @return  the value of the variable/constant
+ * @brief Calculates the value.
+ *
+ * @param value     OUT: the value of the instance
  */
-QVariant RplASScalar::calc()
+void RplASNamedValue::calc(RplASVariant& value)
 {
-    return m_value;
+
 }
 
 /** @class RplASNode1 rplastree.hpp "rplexpr/rplastree.hpp"
@@ -239,6 +431,13 @@ RplASNode1::~RplASNode1()
     delete m_child;
     m_child = NULL;
 }
+/**
+ * @brief Sets the child.
+ */
+void RplASNode1::setChild(RplASItem* child)
+{
+    m_child = child;
+}
 
 /** @class RplASNode2 rplastree.hpp "rplexpr/rplastree.hpp"
  *
@@ -292,50 +491,58 @@ RplASNode3::~RplASNode3()
     m_child3 = NULL;
 }
 
-/** @class RplASBinOp rplastree.hpp "rplexpr/rplastree.hpp"
+/** @class RplASNode4 rplastree.hpp "rplexpr/rplastree.hpp"
  *
- * @brief Implements a binary operator.
+ * @brief Implements a inner node of the abstract syntax tree with 3 childs.
+ *
+ * This class is an abstract class.
  */
+
 /**
- * @brief Constructor.
- *
- * @param op    the operator
+ * @brief RplASNode4::RplASNode4
+ * @param type
  */
-RplASBinOp::RplASBinOp(RplASBinaryOperator op) :
-    RplASNode2(type),
-    m_op(op)
+RplASNode4::RplASNode4(RplASItemType type) :
+    RplASNode3(type),
+    m_child4(NULL)
 {
 }
+
 /**
  * @brief Destructor.
  */
-RplASUnaryOp::~RplASBinOp()
+RplASNode4::~RplASNode4()
 {
+    delete m_child4;
+    m_child4 = NULL;
 }
 
 /** @class RplASUnaryOp rplastree.hpp "rplexpr/rplastree.hpp"
  *
- * @brief Implements a unary operator.
+ * @brief Implements a unary operation.
+ *
+ * This is a operation with one operand, e.g. the boolean not operation.
  */
 
 /**
  * @brief Constructor.
- *
- * @param op    operator
  */
-RplASUnaryOp::RplASUnaryOp(RplASUnaryOperator op) :
-    RplASItem(AST_UNOP),
-    m_op(op)
+RplASUnary::RplASUnaryOp(int op) :
+    m_operator(op)
 {
 }
+
 /**
- * @brief Destructor.
+ * @brief Returns the operator of the unary operation.
+ *
+ * @return the operator
  */
-RplASUnaryOp::~RplASUnaryOp()
+int RplASUnary::getOperator() const
 {
-
+    return m_operator;
 }
 
+
 /** @class RplASStatement rplastree.hpp "rplexpr/rplastree.hpp"
  *
  * @brief Implements a base class for all statements.
@@ -359,6 +566,59 @@ RplASStatement::~RplASStatement()
     m_successor = NULL;
 }
 
+
+/** @class RplASCondition rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a condition.
+ *
+ * The condition is a statement and a RplASExpr and will be used in other
+ * statements like for and while.
+ *
+ */
+/**
+ * @brief Constructor.
+ */
+RplASCondition::RplASCondition() :
+    RplASNode1(AST_CONDITION),
+    RplASCalculable()
+{
+}
+
+void RplASCondition::calc(RplASVariant& value)
+{
+    value.setBool(false);
+    RplASCalculable* node = dynamic_cast<RplASCalculable*>(m_child);
+    if (node == NULL)
+        throw RplASException(m_position, "child of condition is not calculable");
+    node->calc(value);
+}
+/**
+ * @brief Calculates the boolean value and returns it.
+ *
+ * @return the boolean value of the expression
+ */
+bool RplASCondition::calcAsBool()
+{
+    bool rc = false;
+    RplASVariant value;
+    calc(value);
+    switch(value.m_dataType){
+    case RplASVariant::DT_FLOAT:
+        rc = value.m_value.m_float == 0;
+        break;
+    case RplASVariant::DT_BOOL:
+        rc = value.m_value.m_bool;
+        break;
+    case RplASVariant::DT_OBJECT:
+        rc = value.m_class->boolValueOf(value.m_value.m_object);
+        break;
+    default:
+        rc = false;
+        break;
+    }
+    return rc;
+}
+
 /** @class RplASFor rplastree.hpp "rplexpr/rplastree.hpp"
  *
  * @brief Implements a for statement.
@@ -374,7 +634,7 @@ RplASStatement::~RplASStatement()
  * @brief Constructor.
  */
 RplASFor::RplASFor() :
-    RplASNode3(AST_FOR),
+    RplASNode4(AST_FOR),
     RplASStatement()
 {
 }
@@ -385,10 +645,34 @@ RplASFor::~RplASFor()
 {
 }
 
+/**
+ * @brief Executes the statement.
+ *
+ * Meaning of the childs:
+ * m_child: initialization
+ * m_child2: condition
+ * m_child3: forwarding statement
+ * m_child4: body
+ */
 void RplASFor::execute()
 {
     ((RplASStatement*) m_child)->execute();
-    RplASTerm* condition = (RplASTerm* condition)RplASTerm
+    RplASCondition* condition = dynamic_cast<RplASCondition*>(m_child2);
+    if (condition == NULL)
+        throw RplASException(m_child2 == NULL ? m_position : m_child2->position(),
+                             "for statement: not a condition");
+    RplASStatement* forwarding = dynamic_cast<RplASStatement*>(m_child3);
+    if (forwarding == NULL)
+        throw RplASException(m_child3 == NULL ? m_position : m_child3->position(),
+                             "for statement: forwarding is not a statement");
+    RplASStatement* body = dynamic_cast<RplASStatement*>(m_child4);
+    if (body == NULL)
+        throw RplASException(m_child4 == NULL ? m_position : m_child4->position(),
+                             "for statement: body is not a statement");
+    while(condition->calcAsBool()){
+        body->execute();
+        forwarding->execute();
+    }
 }
 
 /** @class RplASWhile rplastree.hpp "rplexpr/rplastree.hpp"
@@ -426,4 +710,139 @@ RplASClass::RplASClass(const QString& name) :
 {
 }
 
+/**
+ * @brief Return the class name.
+ *
+ * @return the class name
+ */
+const QString& RplASClass::name() const
+{
+    return m_name;
+}
+
+/** @class RplASTree rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a manager for all parts of an Abstract Syntax Tree.
+ *
+ * It contains the global symbol space and maintainance a list of used modules.
+ */
+
+/**
+ * @brief Constructor.
+ */
+RplASTree::RplASTree() :
+    // freed in ~RplASTree()
+    m_global(new RplSymbolSpace(RplSymbolSpace::SST_GLOBAL, "global", NULL)),
+    m_modules(),
+    m_symbolSpaces(),
+    m_currentSpace(m_global)
+{
+    m_symbolSpaces.append(m_global);
+}
+
+/**
+ * @brief Destructor.
+ */
+RplASTree::~RplASTree()
+{
+    SymbolSpaceMap::iterator it;
+    for (it = m_symbolSpaceHeap.begin(); it != m_symbolSpaceHeap.end(); it++){
+        delete it.value();
+    }
+    m_symbolSpaceHeap.clear();
+}
+
+/**
+ * @brief Handles the start of a new module.
+ *
+ * @param name  the module's name
+ * @return      true: the module is new<br>
+ *              false: the module is yet known
+ */
+bool RplASTree::startModule(const QString& name)
+{
+    bool rc = m_modules.contains(name);
+    if (! rc){
+        // m_modules[0] is the "global" symbol space.
+        // freed in ~RplASTree()
+        RplSymbolSpace* space = new RplSymbolSpace(RplSymbolSpace::SST_MODULE,
+            name, m_symbolSpaces[0]);
+        m_symbolSpaceHeap[name] = space;
+        m_modules[name] = space;
+        m_symbolSpaces.append(space);
+        m_currentSpace = space;
+    }
+    return rc;
+}
+
+/**
+ * @brief Handles the end of a module.
+ * @param name  the module's name
+ */
+void RplASTree::finishModule(const QString& name)
+{
+    RplSymbolSpace* top = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+    if (top->name() != name)
+        throw RplException("RplASTree::finishModule(): module is not top: %s",
+                           name.toUtf8().constData());
+    else {
+        m_symbolSpaces.removeLast();
+        // "global" is always the bottom:
+        m_currentSpace = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+    }
+}
+
+/**
+ * @brief Handles the start of a new class definition.
+ * @param name
+ */
+void RplASTree::startClassOrMethod(const QString& name,
+        RplSymbolSpace::SymbolSpaceType type)
+{
+    // the stack m_modules is never empty because of "global" and modules.
+    RplSymbolSpace* parent = m_symbolSpaces[m_symbolSpaces.size() - 1];
+    QString fullName = parent->name() + "." + name;
+    // freed in ~RplASTree()
+    RplSymbolSpace* space = new RplSymbolSpace(type, fullName, parent);
+    m_symbolSpaceHeap[fullName] = space;
+    m_symbolSpaces.append(space);
+    m_currentSpace = space;
+}
+
+/**
+ * @brief Handles the end of a class definition.
+ *
+ * @param name  the name of the class (short form)
+ */
+void RplASTree::finishClassOrMethod(const QString& name)
+{
+    RplSymbolSpace* top = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+    if (! top->name().endsWith("." + name))
+        throw RplException("RplASTree::finishModule(): class is not top: %s",
+                           name.toUtf8().constData());
+    else {
+        m_symbolSpaces.removeLast();
+        // "global" is the bottom always!
+        m_currentSpace = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+    }
+}
+
+/**
+ * @brief Returns the stack of the symbol spaces.
+ *
+ * @return the stack with the active symbol spaces
+ */
+RplASTree::SymbolSpaceStack& RplASTree::symbolSpaces()
+{
+    return m_symbolSpaces;
+}
+/**
+ * @brief Returns the current symbol space (top of the stack).
+ *
+ * @return the current symbol space
+ */
+RplSymbolSpace* RplASTree::currentSpace() const
+{
+    return m_currentSpace;
+}
 
index 690136c64dacdd1f5cdb8d21a5656dcff77f1220..012197c9f7352fd13bc746b53866c2836d11cf28 100644 (file)
 
 enum RplASItemType {
     AST_UNDEF,
-    AST_SCALAR,
-    AST_MATRIX,
-    AST_LIST,
-    AST_MAP,
-    AST_BINOP,
-    AST_UNOP,
-    AST_FUNCTION,
-    AST_CALL,
+    AST_CONSTANT,
+    AST_NAMED_VALUE,
+    AST_METHOD,
+    AST_INTRINSIC_METHOD,
+    AST_METHOD_CALL,
     AST_WHILE,
     AST_IF,
+    AST_CONDITION,
     AST_FOR,
+    AST_COUNTED_FOR,
     AST_SWITCH,
-    AST_STATEMENT
-
+    AST_LEAVE,
+    AST_CONTINUE
 };
 
-enum RplASBinaryOperator {
-    ASOP_UNDEF,
-    ASOP_PLUS,
-    ASOP_MINUS,
-    ASOP_TIMES,
-    ASOP_DIV,
-    ASOP_MOD,
-    ASOP_OR,
-    ASOP_AND,
-    ASOP_GT,
-    ASOP_LT,
-    ASOP_GE,
-    ASOP_LE,
-    ASOP_EQ,
-    ASOP_NE,
-    ASOP_ASSIGN,
-    ASOP_ASSIGN_PLUS,
-    ASOP_ASSIGN_MINUS,
-    ASOP_ASSIGN_TIMES,
-    ASOP_ASSIGN_DIV,
-    ASOP_ASSIGN_MOD
-};
-enum RplASUnaryOperator {
-    ASUOP_UNDEF,
-    ASUOP_PLUS,
-    ASOUP_MINUS,
-    ASUOP_POST_DECREMENT,
-    ASUOP_PRE_DECREMENT,
-    ASUOP_POST_INCREMENT,
-    ASUOP_PRE_INCREMENT
+class RplASException : public RplException {
+public:
+    RplASException(const RplSourcePosition* position, const char* message, ...);
 };
+
 class RplASClass;
+class RplASNamedValue;
+class RplASItem;
+class RplASCondition;
+
 class RplASVariant {
 public:
     enum DataType {
         DT_UNDEF,
-        DT_NUMBER,
-        DT_STRING,
-        DT_MAP,
-        DT_LIST,
+        DT_FLOAT,
+        DT_INTEGER,
+        DT_BOOL,
         DT_OBJECT
     };
-
+    friend class RplASCondition;
 public:
     RplASVariant();
     ~RplASVariant();
     RplASVariant(const RplASVariant& source);
     RplASVariant& operator=(const RplASVariant& source);
+    qreal asFloat() const;
+    int asInt() const;
+    bool asBool() const;
+    void* asObject(const RplASClass** clazz) const;
+    const QString* asString() const;
+    void setFloat(qreal number);
+    void setInt(int integer);
+    void setBool(bool value);
+    void setObject(void* object, const RplASClass* clazz);
+    void setString(const QString& string);
 protected:
     void copyValue(const RplASVariant& source);
     void destroyValue();
 private:
     DataType m_dataType;
     union {
-        qreal m_number;
-        QString* m_string;
-        QMap<QString, RplASVariant*> m_map;
-        QList<RplAsValue*> m_list;
+        qreal m_float;
+        int m_int;
+        bool m_bool;
         void* m_object;
     } m_value;
-    RplASClass* m_class;
+    const RplASClass* m_class;
 };
 
 class RplASTree;
@@ -98,39 +83,55 @@ public:
     friend class RplASTree;
     RplASItem(RplASItemType type);
     virtual ~RplASItem();
-
+public:
+    const RplSourcePosition* position() const;
+    void setPosition(const RplSourcePosition* position);
 protected:
-    RplSourcePosition* m_position;
+    RplASItemType m_type;
+    const RplSourcePosition* m_position;
 };
 
-class RplASExpr
+class RplASCalculable
 {
 public:
-    RplASExpr();
+    RplASCalculable();
 public:
-    virtual QVariant calc() = 0;
+    virtual void calc(RplASVariant& value) = 0;
 };
 
-class RplASValue : public RplASItem, public RplASExpr
+class RplASConstant : public RplASItem, public RplASCalculable
 {
 public:
-    RplASValue(RplASItemType type, const QString& name,
-               boolean isConst);
-    virtual ~RplASValue();
+    RplASConstant();
+public:
+    virtual void calc(RplASVariant& value);
+public:
+    RplASVariant& value();
 private:
-    QString m_name;
-    boolean m_isConst;
+    RplASVariant m_value;
 };
 
-class RplASScalar : public RplASValue
+class RplASNamedValue : public RplASItem, public RplASCalculable
 {
 public:
-    RplASScalar(const QString& name, boolean isConst);
-    virtual ~RplASScalar();
+    enum Attributes {
+        A_NONE,
+        /// the value cannot be changed.
+        A_CONST         = 1<<1,
+        /// the variable/constant is found in the global namespace, not in a method
+        A_GLOBAL        = 1<<2,
+        /// the variable/constant is found in the module namespace, not in a method
+        A_MODULE_STATIC = 1<<3
+    };
+
+public:
+    RplASNamedValue(const QString& name, int attributes = A_NONE);
+    QString name() const;
 public:
-    virtual QVariant calc();
+    virtual void calc(RplASVariant& value);
 private:
-    QVariant m_value;
+    QString m_name;
+    int m_attributes;
 };
 
 class RplASNode1 : public RplASItem
@@ -138,6 +139,8 @@ class RplASNode1 : public RplASItem
 public:
     RplASNode1(RplASItemType type);
     virtual ~RplASNode1();
+public:
+    void setChild(RplASItem* child);
 protected:
     RplASItem* m_child;
 };
@@ -160,22 +163,31 @@ protected:
     RplASItem* m_child3;
 };
 
-class RplASBinOp : public RplASNode2
+class RplASNode4 : public RplASNode3
 {
 public:
-    RplASBinOp(RplASBinaryOperator op);
-    virtual ~RplASBinOp();
-private:
-    RplASBinaryOperator m_op;
+    RplASNode4(RplASItemType type);
+    virtual ~RplASNode4();
+protected:
+    RplASItem* m_child4;
 };
 
-class RplASUnaryOp : public RplASNode1
+class RplASUnary : public RplASNode1
+{
+public:
+    RplASUnaryOp(int op);
+public:
+    int getOperator() const;
+
+private:
+    int m_operator;
+};
+class RplASBinaryOp : public RplASNode2
 {
 public:
-    RplASUnaryOp(RplASUnaryOperator op);
-    virtual ~RplASUnaryOp();
+    RplASBinaryOp();
 private:
-    RplASUnaryOperator m_op;
+    int m_operator;
 };
 
 class RplASStatement
@@ -189,15 +201,22 @@ private:
     RplASItem* m_successor;
 };
 
-class RplASFor : public RplASNode3, public RplASStatement
+class RplASCondition : public RplASNode1, public RplASCalculable
+{
+public:
+    RplASCondition();
+public:
+    void calc(RplASVariant& value);
+    bool calcAsBool();
+};
+
+class RplASFor : public RplASNode4, public RplASStatement
 {
 public:
     RplASFor();
     virtual ~RplASFor();
 public:
     virtual void execute();
-private:
-    RplASStatement* m_body;
 };
 
 class RplASWhile : public RplASNode2, public RplASStatement
@@ -207,20 +226,21 @@ public:
     virtual ~RplASWhile();
 };
 
-class RplArgument : public RplAsNode2, public RplASStatement
+class RplArgument : public RplASNode2, public RplASStatement
 {
 public:
     RplArgument();
     virtual ~RplArgument();
 };
 
+class RplASMethod;
 class RplAsMethodCall : public RplASNode2, public RplASStatement
 {
 public:
-    RplArgument();
-    virtual ~RplArgument();
+    RplAsMethodCall();
+    virtual ~RplAsMethodCall();
 private:
-    RplASFunction* m_function;
+    RplASMethod* m_method;
     RplArgument* m_arg1;
 };
 
@@ -231,12 +251,12 @@ public:
     virtual ~RplParameter();
 private:
     QString m_name;
-    RplASValue* m_default;
+    RplASNamedValue* m_default;
 };
 
 
 class RplASClass;
-class RplASMethod : public RplASNode2, public RplASStatement
+class RplASMethod : public RplASNode2
 {
 public:
     RplASMethod();
@@ -256,26 +276,63 @@ public:
      * @param source    NULL or a source to copy
      * @return          a new value object (specific for the class)
      */
-    void* newValueInstance(void* source = NULL) = 0;
+    virtual void* newValueInstance(void* source = NULL) const = 0;
     /**
-     * @brief Destroyes the given object.
+     * @brief Destroys the given object.
      *
      * The object must be created by <code>newValueInstance()</code>.
      *
      * @param object    object to destroy
      */
-    void destroyValueInstance(void* object) = 0;
+    virtual void destroyValueInstance(void* object) const = 0;
+    /**
+     * @brief Returns the boolean value of a class specific value.
+     *
+     * Example: the boolean value of an the empty string is false
+     *
+     * @param object    object to test
+     * @return          false: the object represents the false value<br>
+     *                  true: otherwise
+     */
+    virtual bool boolValueOf(void* object) const = 0;
+public:
+    const QString& name() const;
 protected:
     QString m_name;
-    QMap<String, RplASMethod*> m_methods;
-    RplASClass* m_superClass;
+    QMap<QString, RplASMethod*> m_methods;
+    const RplASClass* m_superClass;
 };
 
-
+#include "rplexpr/rplasclasses.hpp"
+class RplSymbolSpace;
 class RplASTree
 {
+public:
+    typedef QMap<QString, RplSymbolSpace*> SymbolSpaceMap;
+    typedef QList<RplSymbolSpace*> SymbolSpaceStack;
 public:
     RplASTree();
+    ~RplASTree();
+public:
+    bool startModule(const QString& name);
+    void finishModule(const QString& name);
+    void startClassOrMethod(const QString& name,
+        RplSymbolSpace::SymbolSpaceType type);
+    void finishClassOrMethod(const QString& name);
+    SymbolSpaceStack& symbolSpaces();
+    RplSymbolSpace* currentSpace() const;
+
+private:
+    // the mother of all symbol spaces.
+    RplSymbolSpace* m_global;
+    // contains all hit modules
+    SymbolSpaceMap m_modules;
+    // nested modules (import), classes and methods build this stack:
+    SymbolSpaceStack m_symbolSpaces;
+    // top of the stack:
+    RplSymbolSpace* m_currentSpace;
+    // contain all ever built symbol spaces:
+    SymbolSpaceMap m_symbolSpaceHeap;
 };
 
 #endif // RPLASTREE_HPP
index 64b2cebb04df7043226278f9c962b841f3f7f5a9..18a9cf6bfd47c21425f405957cb6cd2424b45a40 100644 (file)
@@ -21,6 +21,7 @@
 #include "rplexpr/rplsource.hpp"
 #include "rplexpr/rpllexer.hpp"
 #include "rplexpr/rplastree.hpp"
-#include "rplexpr/rplasclasses.hpp"
+#include "rplexpr/rplvm.hpp"
+#include "rplexpr/rplmfparser.hpp"
 
 #endif // RPLEXPR_HPP
index 1bf42b5601cf10fbe9d526f49e07a25b525ec46c..a2d7e29f50167539b93a2e3ef42ebf80ce985dbf 100644 (file)
 #include "rplexpr/rplexpr.hpp"
 
 #define CHAR_INFO_SIZE (int(sizeof m_charInfo / sizeof m_charInfo[0]))
+
 /** @class RplToken rpllexer.hpp "rplexpr/rpllexer.hpp"
  *
- * @brief Implements a token which is the smallest unit for a parser.
+ * @brief Implements specific exception for the lexer.
  *
  */
 
@@ -40,6 +41,11 @@ RplLexException::RplLexException(RplSourcePosition& position,
     m_message += buffer;
 }
 
+/** @class RplToken rpllexer.hpp "rplexpr/rpllexer.hpp"
+ *
+ * @brief Implements a token which is the smallest unit for a parser.
+ *
+ */
 /**
  * @brief Constructor.
  * @param type  token type
@@ -184,7 +190,7 @@ void RplToken::clear()
  *
  */
 
-static void itemsToVector(const char* items, QVector<QString>& vector,
+static void itemsToVector(const char* items, RplLexer::StringList& vector,
                          int firstCharFlag, int secondCharFlag,
                          int thirdCharFlag, int restCharFlag,
                          int charInfo[])
@@ -376,7 +382,7 @@ void RplLexer::initializeComments(const char* comments)
  * @param id            the id of the entry in the vector. Only set if found
  * @return
  */
-int RplLexer::findInVector(int tokenLength, const QVector<QString>& vector)
+int RplLexer::findInVector(int tokenLength, const StringList& vector)
 {
     int id = 0;
     int lbound = 0;
@@ -456,7 +462,7 @@ bool RplLexer::fillInput()
  *                  otherwise: the token
  */
 RplToken* RplLexer::findTokenWithId(RplTokenType tokenType, int flag2,
-                                   QVector<QString>& names)
+                                   StringList& names)
 {
     int length = 1;
     int inputLength = m_input.size();
@@ -795,6 +801,28 @@ RplToken* RplLexer::nextToken()
     }
     return rc;
 }
+/**
+ * @brief Makes that nextToken() returns the current token again.
+ */
+void RplLexer::undoLastToken()
+{
+    m_waitingToken = m_currentToken;
+    m_currentToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
+    m_currentPosition = m_currentPosition == &m_position1
+            ? &m_position2 : &m_position1;
+
+}
+
+/**
+ * @brief Returns the next relevant token, but the token remains "unread".
+ *
+ * @return the next token which is not a space/comment
+ */
+RplToken*RplLexer::peekNonSpaceToken()
+{
+    nextNonSpaceToken();
+    undoLastToken();
+}
 /**
  * @brief Returns the maximal length of a token
  * @return  the maximal length of a token
index 8d8771070a75c56098e3f7f197074101d31da4ca..e9ff9d7c4f494be8c6a6c1e8c930f89768b1b285 100644 (file)
@@ -69,6 +69,7 @@ class RplSource;
 class RplLexer
 {
 public:
+    typedef QList<QString> StringList;
     enum NumericType {
         NUMTYPE_UNDEF,
         NUMTYPE_DECIMAL     = 1 << 0,
@@ -125,7 +126,7 @@ public:
         SF_QUOTE        = 1 << 2,
         /// character escaping like in C: \<char> is <char>
         SF_C_ESCAPING   = 1 << 3,
-        /// special characters like in C: \r \f \r \t
+        /// special characters like in C: \r \f \n \t \a
         SF_C_SPECIAL    = 1 << 4,
         /// characters can be written in hexadecimal notation: \x20 is ' '
         SF_C_HEX_CHARS  = 1 << 5,
@@ -162,6 +163,7 @@ public:
     virtual ~RplLexer();
 public:
     RplToken* nextToken();
+    void undoLastToken();
     RplToken* peekNonSpaceToken();
     RplToken* nextNonSpaceToken();
     size_t maxTokenLength() const;
@@ -172,23 +174,23 @@ private:
     void prepareOperators(const char* operators);
     void initializeComments(const char* comments);
     bool fillInput();
-    int findInVector(int tokenLength, const QVector<QString>& vector);
+    int findInVector(int tokenLength, const StringList& vector);
     const char* nextText(int& length, bool &isLast);
     RplToken* findTokenWithId(RplTokenType tokenType, int flag2,
-                              QVector<QString>& names);
+                              StringList& names);
     RplToken* scanNumber();
     RplToken* scanString();
     void scanComment();
 protected:
     RplSource* m_source;
     /// sorted, string ends with the id of the keyword
-    QVector<QString> m_keywords;
+    StringList m_keywords;
     // sorted, string ends with the id of the operator
-    QVector<QString> m_operators;
+    StringList m_operators;
     // sorted, each entry ends with the id of the comment start
-    QVector<QString> m_commentStarts;
+    StringList m_commentStarts;
     // index: id content: comment_end
-    QVector<QString> m_commentEnds;
+    StringList m_commentEnds;
     // index: ord(char) content: a sum of CharClassTags
     int m_charInfo[128];
     // a list of QChars with ord(cc) > 127 and which can be the first char
diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp
new file mode 100644 (file)
index 0000000..57d3898
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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 "rplexpr/rplexpr.hpp"
+
+/** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp"
+ *
+ * @brief Implements a parser for the language MF.
+ *
+ * MF stands for Mathe Fan or Multiple Faces or ....
+ * This is an universal object oriented programming language with extension
+ * for matrix operations, simulation and graphics.
+ */
+
+RplMFParser::RplMFParser(RplSource& source) :
+    m_lexer(&source,
+            MF_KEYWORDS, MF_OPERATORS,
+            "/* */ // \n",
+            "a-zA-Z_", "a-zA-Z0-9_",
+            NUMTYPE_ALL, SF_C_ALL
+            )
+{
+}
+
+/**
+ * @brief Parses a function or a generator.
+ */
+void RplMFParser::parseFunc()
+{
+
+}
+/**
+ * @brief Parses an if statement.
+ */
+void RplMFParser::parseIf()
+{
+
+}
+/**
+ * @brief Parses a while statement.
+ */
+
+void RplMFParser::parseWhile()
+{
+
+}
+
+/**
+ * @brief Parses a repeat statement.
+ */
+void RplMFParser::parseRepeat()
+{
+
+}
+
+/**
+ * @brief Parses a for statement.
+ */
+void RplMFParser::parseFor()
+{
+
+}
+
+/**
+ * @brief Parses a variable definition.
+ *
+ * @param clazz     NULL or the type of the variable
+ * @param attribute 0 or attribute of the variable: K_CONST or K_LAZY
+ */
+void RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute = K_UNDEF)
+{
+
+}
+
+/**
+ * @brief Parses an operand.
+ * An operand is the first and the third part of an binary operation.
+ * Examples: constant, variable, method call
+ *
+ * @return  the node with the operand
+ */
+RplASItem* RplMFParser::parseOperand(int level)
+{
+    RplToken* token = m_lexer->nextNonSpaceToken();
+    RplASItem* rc = NULL;
+    switch(token->tokenType()){
+    case TOKEN_OPERATOR:
+        rc = new RplASUnary(token->id());
+        rc->setChild(parseOperand);
+        break;
+    case TOKEN_STRING:
+    case TOKEN_NUMBER:
+    case TOKEN_REAL:
+    {
+        RplASConstant constant = new RplASConstant();
+        item = constant;
+        switch(token->tokenType()){
+        case TOKEN_STRING:
+            constant.m_value.setString(token->toString());
+            break;
+        case TOKEN_NUMBER:
+            constant.m_value.setInt(token->asInteger());
+            break;
+        case TOKEN_REAL:
+            constant.m_value.setFloat(token->asReal());
+            break;
+        default:
+            break;
+        }
+        break;
+    }
+    case TOKEN_ID:
+    {
+        QString name = token->toString();
+        token = m_lexer->nextNonSpaceToken();
+        if (token->tokenType() != TOKEN_OPERATOR){
+            RplASNamedValue* var = new RplASNamedValue(name);
+            item = var;
+            m_lexer->undoLastToken();
+        } else {
+            if (token->id() == m_tokenParenthesis){
+                RplASItem* args = parseArguments();
+                RplAsMethodCall =
+            } else if (token->id() == m_tokenDecrement){
+                RplASNamedValue* var = new RplASNamedValue(name);
+                item = var;
+
+            }
+        }
+        break;
+    }
+    default:
+        break;
+    }
+    return item;
+}
+
+/**
+ * @brief Parses a term.
+ *
+ * A term is a part of an expression with the same parenthesis level.
+ * Example: a + (3 * 7 - 2)<br>
+ * first term: 3*7-2<br>
+ * second term: a + term1<br>
+ *
+ * @param depth     the level of the parenthesis
+ * @return
+ */
+RplASItem* RplMFParser::parseTerm(int depth){
+    RplToken* token;
+    RplSourcePosition* start = m_lexer->currentSourcePosition();
+    RplASItem* top = NULL;
+    RplASItem* item;
+    bool again = true;
+    do {
+        item = parseOperand(level);
+        token = m_lexer->nextNonSpaceToken();
+        switch(token->tokenType()){
+        case TOKEN_OPERATOR:
+            break;
+        case TOKEN_STRING:
+        case TOKEN_NUMBER:
+        case TOKEN_REAL:
+            break;
+        case TOKEN_KEYWORD:
+        case TOKEN_OPERATOR:
+        case TOKEN_ID:
+        case TOKEN_END_OF_SOURCE:
+            again = false;
+            break;
+        default:
+            break;
+        }
+    } while(again);
+
+}
+
+/**
+ * @brief Parses an expression.
+ *
+ * @precond     the nextNonSpaceToken() will return the first token of the expr.
+ * @postcond    all tokens belonging to the expr are read
+ *
+ * @return      the token behind the expr
+ */
+RplToken* RplMFParser::parseExpr()
+{
+    RplASItem* item = parseTerm(0);
+}
+
+/**
+ * @brief Parses the body.
+ *
+ * A body is a module, a class region or a method body.
+ */
+void RplMFParser::parseBody()
+{
+    RplToken token = m_lexer->nextNonSpaceToken();
+    switch(token.tokenType())
+    {
+    case TOKEN_STRING:
+    case TOKEN_NUMBER:
+    case TOKEN_REAL:
+    case TOKEN_OPERATOR:
+        m_lexer->undoNextToken();
+        token = parseExpr();
+        break;
+    case TOKEN_KEYWORD:
+        switch (token.id()){
+        case K_IF:
+            parseIf();
+            break;
+        case K_WHILE:
+            parseWhile();
+            break;
+        case K_REPEAT:
+            parseRepeat();
+            break;
+        case K_FOR:
+            parseFor();
+            break;
+        case K_CLASS:
+            parseClass();
+            break;
+        case K_FUNCTION:
+        case K_GENERATOR:
+            parseMethod();
+            break;
+        case K_IMPORT:
+            parseImport();
+            break;
+        case K_CONST:
+        case K_LAZY:
+            parseDefinition(NULL, token.id());
+            break;
+        case K_INT:
+            parseDefinition(&RplASInteger.m_instance);
+            break;
+        case K_FLOAT:
+            parseDefinition(&RplASFloat.m_instance);
+            break;
+        case K_BOOL:
+            parseDefinition(&RplASBoolean.m_instance);
+            break;
+        default:
+            break;
+        }
+        break;
+    case TOKEN_ID:
+    {
+        RplASClass* clazz = m_tree.currentSpace()->findClass();
+        if (clazz != NULL){
+             parseDefinition(clazz);
+        } else {
+            m_lexer->undoNextToken();
+            parseExpr();
+        }
+        break;
+    }
+    case TOKEN_END_OF_SOURCE:
+        break;
+    default:
+        break;
+    }
+}
+
+/**
+ * @brief Parses a module.
+ *
+ * @precond     the first char of the module is the next char to read.
+ * @postcond    the total module is read
+ *
+ * @param name  the name of the module (without path)
+ */
+void RplMFParser::parseModule(const QString& name)
+{
+    m_tree.startModule(name);
+    parseBody();
+    m_tree.finishModule(name);
+}
+/**
+ * @brief Parse the input given by the source.
+ */
+void RplMFParser::parse()
+{
+
+}
+
diff --git a/rplexpr/rplmfparser.hpp b/rplexpr/rplmfparser.hpp
new file mode 100644 (file)
index 0000000..73bc712
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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 RPLMFPARSER_HPP
+#define RPLMFPARSER_HPP
+
+class RplMFParser
+{
+public:
+    enum Keyword {
+        K_UNDEF, K_IF, K_THEN, K_ELSE, K_FI, K_WHILE, K_DO, K_OD, K_REPEAT, K_UNTIL,
+        K_FOR, K_FROM, K_TO, K_STEP, K_CASE, K_OF, K_ESAC, K_LEAVE, K_CONTINUE, K_PASS,
+        K_CLASS, K_END, K_FUNCTION, K_GENERATOR, K_IMPORT,
+        K_CONST, K_LAZY, K_INT, K_FLOAT, K_BOOL, K_NONE, K_TRUE, K_FALSE
+         };
+#define MF_KEYWORDS "if then else fi while do od repeat until" \
+    " for from to step case of esac leave continue pass" \
+    " class end function generator import" \
+    " const lazy int float bool None True False"
+    enum Operator {
+        O_UNDEF, O_SEMI_SEMICOLON, O_SEMICOLON, O_COMMA, O_COLON, O_QUESTION,
+        O_OR, O_AND,
+        O_XOR, O_BIT_OR, O_BIT_AND, O_LSHIFT, O_RSHIFT, O_RSHIFT2,
+        O_LT, O_GT, O_LE, O_GE, O_EQ, O_NE,
+        O_PLUS, O_MINUS, O_DIV, O_MOD, O_TIMES, O_POWER, O_INC, O_DEC,
+        O_DOT
+    };
+
+#define MF_OPERATORS ";; ; , : ?" \
+    " || && " \
+    " ^ | & << >> >>>" \
+    " < > <= >= == !=" \
+    " + - / % * ** ++ --" \
+    " ."
+public:
+    RplMFParser(RplSource& source, RplASTree& ast);
+public:
+    void parseFunc();
+    void parseIf();
+    void parseWhile();
+    void parseRepeat();
+    void parseFor();
+    void parseDefinition(RplASClass* clazz);
+    RplToken* parseExpr();
+    void parseBody();
+    void parseClass();
+    void parseModule(const QString& name);
+    void parse();
+    RplASItem* parseOperand();
+    RplASItem* parseTerm(int depth);
+private:
+    RplLexer m_lexer;
+    RplASTree& m_tree;
+};
+
+#endif // RPLMFPARSER_HPP
index 05b0943b8571f487b3570792ce460e53a073c7dc..5e147ff6ac8642d14a67812e371dd3c1dc9db108 100644 (file)
@@ -153,7 +153,9 @@ RplSourcePosition&RplSourcePosition::operator=(const RplSourcePosition& source)
  */
 QString RplSourcePosition::toString() const
 {
-    QString rc = m_sourceUnit->name();
+    QString rc;
+    if (m_sourceUnit != NULL)
+        rc = m_sourceUnit->name();
     QTextStream stream(&rc);
     stream << "-" << m_lineNo << " (" << m_column << "): ";
     return rc;
diff --git a/rplexpr/rplvm.cpp b/rplexpr/rplvm.cpp
new file mode 100644 (file)
index 0000000..8e351c4
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * 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 "rplexpr/rplexpr.hpp"
+
+
diff --git a/rplexpr/rplvm.hpp b/rplexpr/rplvm.hpp
new file mode 100644 (file)
index 0000000..c8f8d62
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 RPLVM_HPP
+#define RPLVM_HPP
+
+class RplStackFrame {
+public:
+    RplStackFrame(int countArgs, int countLocals);
+    ~RplStackFrame();
+public:
+private:
+    RplASVariant* m_variables;
+};
+
+class RPLVirtualMachine
+{
+public:
+    RPLVirtualMachine();
+public:
+    void calc();
+private:
+    RplStackFrame m_global;
+    QMap<QString, RplSymbolSpace*> m_modules;
+    QList<RplStackFrame*> m_stack;
+};
+
+#endif // RPLVM_HPP
index ef9e8716712c52d7cc1c491addabfc7a94c75b49..78d1cd826fb5656e5b4fdccb79529cec7c1efe49 100644 (file)
@@ -34,7 +34,9 @@ SOURCES += \
     ../rplexpr/rplsource.cpp \
     ../rplcore/rplqstring.cpp \
     ../rplexpr/rplastree.cpp \
-    ../rplexpr/rplasclasses.cpp
+    ../rplexpr/rplasclasses.cpp \
+    ../rplexpr/rplmfparser.cpp \
+    ../rplexpr/rplvm.cpp
 
 HEADERS += ../rplmodules.hpp \
     ../rplcore/rplconfig.hpp \
@@ -60,7 +62,9 @@ HEADERS += ../rplmodules.hpp \
     ../rplexpr/rplsource.hpp \
     ../rplcore/rplqstring.hpp \
     ../rplexpr/rplastree.hpp \
-    ../rplexpr/rplasclasses.hpp
+    ../rplexpr/rplasclasses.hpp \
+    ../rplexpr/rplmfparser.hpp \
+    ../rplexpr/rplvm.hpp
 
 unix:!symbian {
     maemo5 {
index 00d80d37b82716b7194b7d52ac2f8fd9d041df9b..274a93c221b7ec51f76a89649b22072e2abce19b 100644 (file)
@@ -22,9 +22,12 @@ void testCore(){
 }
 
 void testExpr(){
+    extern void testRplASTree();
+    testRplASTree();
     extern void testRplSource();
     testRplSource();
-
+    extern void testRplLexer();
+    testRplLexer();
 }
 
 void testStandard(){
@@ -40,9 +43,6 @@ int main(int argc, char *argv[])
     if (argc > 1)
         printf("not used: %s\n", argv[1]);
 
-    extern void testRplLexer();
-    testRplLexer();
-
     testStandard();
 
 }
diff --git a/unittests/rplastree_test.cpp b/unittests/rplastree_test.cpp
new file mode 100644 (file)
index 0000000..a225c84
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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 "rplexpr/rplexpr.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestRplASTree : public RplTest{
+private:
+    RplSource m_source;
+    RplStringReader m_reader;
+    RplStringSourceUnit m_unit;
+public:
+    TestRplASTree() :
+        RplTest("RplASTree"),
+        m_source(),
+        m_reader(m_source),
+        m_unit("<main>", "", &m_reader)
+    {}
+public:
+    void testRplASException() {
+        try{
+            RplSourcePosition pos(&m_unit, 1, 2);
+            throw RplASException(&pos, "simple string: %s", "Hi");
+            checkF(true);
+        } catch (RplASException exc){
+            checkE("<main>-1 (2): simple string: Hi", exc.getMessage().constData());
+        }
+    }
+    void testRplASVariant(){
+        RplASVariant val1;
+        val1.setFloat(2.5E-2);
+        checkE(2.5E-2, val1.asFloat());
+        RplASVariant val2(val1);
+        checkE(2.5E-2, val2.asFloat());
+
+        val1.setInt(4321);
+        checkE(4321, val1.asInt());
+        val2 = val1;
+        checkE(4321, val2.asInt());
+
+        val1.setBool(false);
+        checkF(val1.asBool());
+        val2 = val1;
+        checkF(val2.asBool());
+
+        val1.setBool(true);
+        checkT(val1.asBool());
+        val2 = val1;
+        checkT(val2.asBool());
+
+        val1.setString("High noon!");
+        checkE("High noon!", *val1.asString());
+        val2 = val1;
+        val1.setString("Bye");
+        checkE("High noon!", *val2.asString());
+        RplASVariant val3(val1);
+        checkE("Bye", *val3.asString());
+    }
+    void testRplASConstant(){
+        RplASConstant constant;
+        constant.value().setString("Jonny");
+        RplASVariant value;
+        constant.calc(value);
+        checkE("Jonny", *value.asString());
+    }
+    void testRplASNamedValue(){
+        RplASNamedValue value("gugo");
+        checkE("gugo", value.name());
+    }
+    void testRplASCondition(){
+        RplASCondition cond;
+        RplASConstant* constant = new RplASConstant();
+        constant->value().setString("True");
+        cond.setChild(constant);
+        checkT(cond.calcAsBool());
+        constant->value().setInt(0);
+        checkF(cond.calcAsBool());
+    }
+
+    virtual void doIt() {
+        testRplASCondition();
+        testRplASNamedValue();
+        testRplASConstant();
+        testRplASException();
+        testRplASVariant();
+    }
+};
+void testRplASTree() {
+    TestRplASTree test;
+    test.run();
+}
+
+
+
+
+
+
index 9857e135762a1b60a6b723fc5981d3160370b259..b32f701ba29864a634bbf7fd29c779956a06b955 100644 (file)
@@ -62,7 +62,7 @@ public:
     }
 
     void testToArray() {
-        QVector<QByteArray> array = RplString::toArray("1 abc 3", " ");
+        QList<QByteArray> array = RplString::toArray("1 abc 3", " ");
         checkE(3, array.size());
         checkE("1", array.at(0));
         checkE("abc", array.at(1));
index 61f3e81462d28bd4949b4b15d5b39042c37f4686..6edd0ecd413d1708346227415ace05a1321f970d 100644 (file)
@@ -32,5 +32,6 @@ SOURCES += main.cpp \
     rpllexer_test.cpp \
     rplqstring_test.cpp \
     ../rplcore/rplqstring.cpp \
-    ../rplexpr/rplasclasses.cpp
+    ../rplexpr/rplasclasses.cpp \
+    rplastree_test.cpp