string functions
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 28 Nov 2010 15:05:13 +0000 (15:05 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 28 Nov 2010 15:05:13 +0000 (15:05 +0000)
git-svn-id: https://silmor.de/svn/softmagic/elam/trunk@640 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

src/elam.h
src/elam.pro
src/elamstringengine.cpp [new file with mode: 0644]
src/elamstringengine.h [new file with mode: 0644]
tests/parser/parser.cpp
tests/parser/parser.h

index 165abc9..0bb9253 100644 (file)
@@ -10,6 +10,7 @@
 #include "elamintengine.h"
 #include "elamfloatengine.h"
 #include "elamboolengine.h"
+#include "elamstringengine.h"
 
 /** \mainpage ELAM - Elementary Logic and Arithmetic Machine
 
index 690e18f..2d4f42a 100644 (file)
@@ -19,7 +19,8 @@ HEADERS += \
        elamvalue.h \
        elamintengine.h \
        elamfloatengine.h \
-       elamboolengine.h
+       elamboolengine.h \
+       elamstringengine.h
 
 SOURCES += \
        elamvalue.cpp \
@@ -30,7 +31,8 @@ SOURCES += \
        elamintengine.cpp \
        elamexpression.cpp \
        elamfloatengine.cpp \
-       elamboolengine.cpp
+       elamboolengine.cpp \
+       elamstringengine.cpp
 
 INCLUDEPATH += .
 DEPENDPATH += .
diff --git a/src/elamstringengine.cpp b/src/elamstringengine.cpp
new file mode 100644 (file)
index 0000000..aee1e40
--- /dev/null
@@ -0,0 +1,166 @@
+// ELAM int engine definition implementation
+//
+// (c) Konrad Rosenbaum, 2010
+// protected under the GNU LGPL v3 or at your option any newer
+
+#include "elamstringengine.h"
+
+#include<QDebug>
+
+using namespace ELAM;
+
+StringEngine::StringEngine()
+{
+       configureStringEngine(*this);
+}
+
+static QString unescape(QString ls)
+{
+       QString r,cd;
+       enum {Normal,BSlash,Octal,Hexa}mode=Normal;
+       for(int i=0;i<ls.size();i++){
+               if(mode==BSlash){
+                       switch(ls[i].unicode()){
+                               case '\\':r+='\\';break;
+                               case 'n':r+='\n';break;
+                               case 'r':r+='\r';break;
+                               case 't':r+='\t';break;
+                               case 'v':r+='\v';break;
+                               case 'b':r+='\b';break;
+                               case 'f':r+='\f';break;
+                               case 'a':r+='\a';break;
+                               case '\'':r+='\'';break;
+                               case '\"':r+='\"';break;
+                               case '0':case '1':case '2':
+                               case '3':case '4':case '5':
+                               case '6':case '7':
+                                       mode=Octal;
+                                       cd=ls[i];
+                                       break;
+                               case 'x':
+                                       mode=Hexa;
+                                       cd.clear();
+                                       break;
+                               case 'u':
+                                       cd=ls.mid(i+1,4); i+=4;
+                                       r+=QChar(cd.toInt(0,16));
+                                       mode=Normal;
+                                       break;
+                               case 'U':
+                                       cd=ls.mid(i+1,8); i+=8;
+                                       r+=QChar(cd.toInt(0,16));
+                                       mode=Normal;
+                                       break;
+                               default:
+                                       r+=ls[i];
+                                       break;
+                       }
+                       if(mode==BSlash)mode=Normal;
+               }else if(mode==Octal){
+                       if(ls[i]>='0' && ls[i]<='7')
+                               cd+=ls[i];
+                       else mode=Normal;
+                       if(cd.size()>=3)
+                               mode=Normal;
+                       if(mode==Normal)
+                               r+=QChar(cd.toInt(0,8));
+               }else if(mode==Hexa){
+                       if((ls[i]>='0' && ls[i]<='9') ||
+                          (ls[i]>='a'&&ls[i]<='f') ||
+                          (ls[i]>='A'&&ls[i]<='F'))
+                               cd+=ls[i];
+                       else mode=Normal;
+                       if(cd.size()>=2)
+                               mode=Normal;
+                       if(mode==Normal)
+                               r+=QChar(cd.toInt(0,16));
+               }else{
+                       if(ls[i]!='\\')r+=ls[i];
+                       else mode=BSlash;
+               }
+       }
+       return r;
+}
+
+//types of int
+// decimal: [1-9][0-9]*
+// octal: 0[0-7]*
+// hex: 0x[0-9a-fA-F]+
+// end of expression: anything not a nameClass.second
+static QPair<QString,QVariant> strLiteralParser(const QString&expr,Engine&engine,int start)
+{
+       Q_UNUSED(engine);
+       QString ls;
+       QChar startc=expr[start];
+       QChar prev='\\';
+       //parse to end of expression
+       bool foundend=false;
+       for(int i=start;i<expr.size();i++){
+               ls+=expr[i];
+               if(expr[i]==startc && prev!='\\'){
+                       foundend=true;
+                       break;
+               }
+               prev=expr[i];
+       }
+       //found it?
+       if(!foundend)
+               return QPair<QString,QVariant>();
+       //convert
+       QString r=unescape(ls.mid(1,ls.size()-2));
+       //return result
+       return QPair<QString,QVariant>(ls,r);
+}
+
+static QVariant strFunc(const QList<QVariant>&lf)
+{
+       if(lf.size()!=1)
+               return Exception(Exception::ArgumentListError, "expecting exactly one argument");
+       if(!lf[0].canConvert<QString>())
+               return Exception(Exception::TypeMismatchError,"cannot convert to string");
+       return lf[0].toString();
+}
+
+static QVariant strlenFunc(const QList<QVariant>&lf)
+{
+       if(lf.size()!=1)
+               return Exception(Exception::ArgumentListError, "expecting exactly one argument");
+       if(!lf[0].canConvert<QString>())
+               return Exception(Exception::TypeMismatchError,"cannot convert to string");
+       return (qlonglong)lf[0].toString().size();
+}
+
+static QVariant concatFunc(const QList<QVariant>&lf)
+{
+       QString ret;
+       for(int i=0;i<lf.size();i++)
+               ret+=lf[i].toString();
+       return ret;
+}
+//additive
+static QVariant strAdd(const QVariant&o1,const QVariant&o2)
+{
+       return o1.toString()+o2.toString();
+}
+
+int StringEngine::stringParserPrio()
+{
+       return 50;
+}
+
+void StringEngine::configureStringEngine(Engine& eng)
+{
+       int sid=QVariant::String;
+       int aid=AnyType::metaTypeId();
+       //parser
+       eng.setLiteralParser(strLiteralParser,"\'\"",stringParserPrio());
+       //cast
+       eng.setFunction("string",strFunc);
+       //other functions
+       eng.setFunction("strlen",strlenFunc);
+       eng.setFunction("concat",concatFunc);
+       //operators
+       eng.binaryOperator("+",80).setCallback(strAdd,sid,sid);
+       eng.binaryOperator("+",80).setCallback(strAdd,aid,sid);
+       eng.binaryOperator("+",80).setCallback(strAdd,sid,aid);
+}
diff --git a/src/elamstringengine.h b/src/elamstringengine.h
new file mode 100644 (file)
index 0000000..de35cd9
--- /dev/null
@@ -0,0 +1,29 @@
+//ELAM string engine header
+//
+// (c) Konrad Rosenbaum, 2010
+// protected under the GNU LGPL v3 or at your option any newer
+
+#ifndef ELAM_STRENGINE_H
+#define ELAM_STRENGINE_H
+
+#include "elamengine.h"
+
+namespace ELAM {
+
+///integer math enabled engine
+class StringEngine:public Engine
+{
+       public:
+               ///instantiates a pre-configured engine
+               StringEngine();
+               
+               ///configures any engine to support basic int math
+               static void configureStringEngine(Engine&);
+               
+               ///returns the default priority of the int literal parser
+               static int stringParserPrio();
+};
+
+};
+
+#endif
index 7cbe8e6..fef435b 100644 (file)
@@ -98,5 +98,21 @@ void ElamTest::tokenizer()
        QCOMPARE(tl[14].type(),Token::ParClose);//)
 }
 
+void ElamTest::stringLiteral()
+{
+       StringEngine se;
+       IntEngine::configureIntEngine(se);
+       QList<Token>tl=se.tokenize("\"\\0123\\u12abcd\"");
+       QString v=QString("\012")+"3"+QChar(0x12ab)+QString("cd");
+       QCOMPARE(tl.size(),1);
+       QCOMPARE(tl[0].isLiteral(),true);
+       QString l=tl[0].literalValue().toString();
+//     qDebug()<<"v="<<v<<"l="<<l;
+       QCOMPARE(v,l);
+       QCOMPARE(se.evaluate("strlen(\"abc\")").toInt(),3);
+       QVariant v2=se.evaluate("concat(\"abc\",12)");
+       QCOMPARE(v2.toString(),QString("abc12"));
+}
+
 
 QTEST_MAIN(ElamTest)
\ No newline at end of file
index 3c0e398..ca5571d 100644 (file)
@@ -6,4 +6,5 @@ class ElamTest:public QObject
        private slots:
                void charClass();
                void tokenizer();
+               void stringLiteral();
 };