diff options
Diffstat (limited to 'src/declarative/qml/script')
-rw-r--r-- | src/declarative/qml/script/generator/generator.pro | 11 | ||||
-rw-r--r-- | src/declarative/qml/script/generator/main.cpp | 135 | ||||
-rw-r--r-- | src/declarative/qml/script/instructions.h | 32 | ||||
-rw-r--r-- | src/declarative/qml/script/keywords.cpp | 89 | ||||
-rw-r--r-- | src/declarative/qml/script/lexer.cpp | 139 | ||||
-rw-r--r-- | src/declarative/qml/script/lexer.h | 54 | ||||
-rw-r--r-- | src/declarative/qml/script/qmlbasicscript.cpp | 923 | ||||
-rw-r--r-- | src/declarative/qml/script/qmlbasicscript.h | 76 | ||||
-rw-r--r-- | src/declarative/qml/script/qmlbasicscript_p.h | 52 | ||||
-rw-r--r-- | src/declarative/qml/script/script.pri | 11 | ||||
-rw-r--r-- | src/declarative/qml/script/tokens.cpp | 44 | ||||
-rw-r--r-- | src/declarative/qml/script/tokens.h | 36 |
12 files changed, 1602 insertions, 0 deletions
diff --git a/src/declarative/qml/script/generator/generator.pro b/src/declarative/qml/script/generator/generator.pro new file mode 100644 index 0000000..1b2a4c7 --- /dev/null +++ b/src/declarative/qml/script/generator/generator.pro @@ -0,0 +1,11 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Mon Apr 2 20:15:52 2007 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +# Input +SOURCES += main.cpp diff --git a/src/declarative/qml/script/generator/main.cpp b/src/declarative/qml/script/generator/main.cpp new file mode 100644 index 0000000..676671f --- /dev/null +++ b/src/declarative/qml/script/generator/main.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <QList> +#include <QByteArray> + + +QT_BEGIN_NAMESPACE +struct Keyword { + const char *lexem; + const char *token; +}; + +struct State +{ + State(const char* token) : token(token) + { + ::memset(next, 0, sizeof(next)); + } + State(const State &other) : token(other.token) + { + ::memcpy(next, other.next, sizeof(next)); + } + State &operator=(const State &other) + { + token = other.token; + ::memcpy(next, other.next, sizeof(next)); + return *this; + } + + QByteArray token; + int next[128]; +}; + +Keyword keywords[] = +{ + {"<", "LANGLE" }, + {">", "RANGLE" }, + {"+", "PLUS" }, + {"-", "MINUS" }, + {"*", "STAR" }, + {"==", "EQUALS" }, + {"&&", "AND" }, + {".", "DOT"}, + {"true", "TOKEN_TRUE"}, + {"false", "TOKEN_FALSE"}, + {" ", "WHITESPACE"}, + {"\t", "WHITESPACE"}, + {0, 0} +}; + +bool is_character(char s) +{ + return (s >= 'a' && s <= 'z') || + (s >= 'A' && s <= 'Z') || + (s >= '0' && s <= '9') || + s == '_'; +} + +void newState(QList<State> &states, const char *token, const char *lexem) +{ + int state = 0; + bool character = is_character(*lexem); + + while(*lexem) { + int next = states[state].next[(int)*lexem]; + + if(!next) { + next = states.size(); + states += State(character?"CHARACTER":"INCOMPLETE"); + states[state].next[(int)*lexem] = next; + } + + state = next; + ++lexem; + character = character && is_character(*lexem); + } + + states[state].token = token; +} + +void newState(QList<State> &states, const char *token, char lexem) +{ + int next = states[0].next[(int)lexem]; + if(!next) { + next = states.size(); + states += State(token); + states[0].next[(int)lexem] = next; + } else { + states[next].token = token; + } +} + +int main() +{ + QList<State> states; + states += State("NOTOKEN"); + + // identifiers + for (int cc = 'a'; cc <= 'z'; ++cc) + newState(states, "CHARACTER", cc); + for (int cc = 'A'; cc <= 'Z'; ++cc) + newState(states, "CHARACTER", cc); + newState(states, "CHARACTER", '_'); + + // add digits + for(int cc = '0'; cc <= '9'; ++cc) + newState(states, "DIGIT", cc); + + // keywords + for(int ii = 0; keywords[ii].lexem; ++ii) + newState(states, keywords[ii].token, keywords[ii].lexem); + + ::printf("static const struct\n{\n" + " Token token;\n" + " char next[128];\n" + "} keywords[] = {\n"); + + for(int ii = 0; ii < states.size(); ++ii) { + printf("%s { %s, { ", ii?",\n":"", states[ii].token.data()); + for(int jj = 0; jj < 128; jj++) + printf("%s%d", jj?",":"", states[ii].next[jj]); + printf(" } }"); + } + + printf("\n};\n"); +} +QT_END_NAMESPACE diff --git a/src/declarative/qml/script/instructions.h b/src/declarative/qml/script/instructions.h new file mode 100644 index 0000000..a21cbce --- /dev/null +++ b/src/declarative/qml/script/instructions.h @@ -0,0 +1,32 @@ +#ifndef _INSTRUCTIONS_H_ +#define _INSTRUCTIONS_H_ + +struct ScriptInstruction { + enum { + Load, // fetch + Fetch, // fetch + + Add, // NA + Subtract, // NA + Multiply, // NA + Equals, // NA + And, // NA + + Int, // integer + Bool, // boolean + } type; + + union { + struct { + int idx; + } fetch; + struct { + int value; + } integer; + struct { + bool value; + } boolean; + }; +}; + +#endif // _INSTRUCTIONS_H_ diff --git a/src/declarative/qml/script/keywords.cpp b/src/declarative/qml/script/keywords.cpp new file mode 100644 index 0000000..4cde65b --- /dev/null +++ b/src/declarative/qml/script/keywords.cpp @@ -0,0 +1,89 @@ +static const struct +{ + Token token; + char next[128]; +} keywords[] = { + { NOTOKEN, { 0,0,0,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,0,0,0,0,0,71,0,0,0,68,66,0,67,73,0,54,55,56,57,58,59,60,61,62,63,0,0,64,69,65,0,0,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,0,0,0,0,53,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { LANGLE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { RANGLE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { PLUS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { MINUS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { STAR, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { INCOMPLETE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { EQUALS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { INCOMPLETE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { AND, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DOT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { TOKEN_TRUE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { TOKEN_FALSE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { WHITESPACE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { WHITESPACE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } +}; diff --git a/src/declarative/qml/script/lexer.cpp b/src/declarative/qml/script/lexer.cpp new file mode 100644 index 0000000..d3ef935 --- /dev/null +++ b/src/declarative/qml/script/lexer.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <QByteArray> +#include "lexer.h" +#include "keywords.cpp" +#include <QDebug> + + +QT_BEGIN_NAMESPACE +QList<LexerToken> tokenize(const char *text) +{ + QList<LexerToken> rv; + + int lineNo = 0; + int charNo = 0; + int state = 0; + int tokenStart = 0; + bool other = false; + + const char *textprog = text; + + bool done = false; + while (!done) { + char textchar = *textprog; + done = !textchar; + + if (other) { + if (keywords[state].next[(int)textchar]) { + + // Do other token + LexerToken token; + token.token = OTHER; + token.start = tokenStart; + token.end = textprog - text - 1; + token.line = lineNo + 1; + token.offset = charNo - (token.end - token.start); + tokenStart = token.end + 1; + rv.append(token); + other = false; + + } else { + goto continue_loop; + } + } + + if (keywords[state].next[(int)textchar]) { + + state = keywords[state].next[(int)textchar]; + + } else if (0 == state || + keywords[state].token == INCOMPLETE) { + + other = true; + if (keywords[state].token == INCOMPLETE) { + state = 0; + continue; + } + + } else { + + // Token completed + Token tokenType = keywords[state].token; + bool tokenCollapsed = false; + if (tokenType == CHARACTER || + tokenType == DIGIT || + tokenType == WHITESPACE) { + + Token lastTokenType = + rv.isEmpty()?NOTOKEN:rv.last().token; + if (tokenType == lastTokenType) { + + rv.last().end = textprog - text - 1; + tokenStart = rv.last().end + 1; + + tokenCollapsed = true; + } + } + + if (!tokenCollapsed) { + LexerToken token; + token.token = keywords[state].token; + token.start = tokenStart; + token.end = textprog - text - 1; + token.line = lineNo + 1; + token.offset = charNo - (token.end - token.start); + tokenStart = token.end + 1; + rv.append(token); + } + + state = keywords[0].next[(int)textchar]; + if (0 == state) + other = true; + } + +continue_loop: + // Reset error reporting variables + if (textchar == '\n') { + ++lineNo; + charNo = 0; + } else { + charNo++; + } + + // Increment ptrs + ++textprog; + } + + if (other && ((textprog - text - 1) != tokenStart)) { + // Do other token + LexerToken token; + token.token = OTHER; + token.start = tokenStart; + token.end = textprog - text - 1; + token.line = lineNo + 1; + token.offset = charNo - (token.end - token.start); + tokenStart = token.end + 1; + rv.append(token); + other = false; + } + return rv; +} + +void dumpTokens(const char *text, const QList<LexerToken> &tokens) +{ + for (int ii = 0; ii < tokens.count(); ++ii) { + QByteArray ba(text + tokens.at(ii).start, tokens.at(ii).end - tokens.at(ii).start + 1); + qWarning() << tokens.at(ii).line << ":" << tokens.at(ii).offset << tokenToString(tokens.at(ii).token) << "(" << tokens.at(ii).start << "-" << tokens.at(ii).end << ")" << ba; + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/script/lexer.h b/src/declarative/qml/script/lexer.h new file mode 100644 index 0000000..7781ee8 --- /dev/null +++ b/src/declarative/qml/script/lexer.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef LEXER_H +#define LEXER_H + +#include <QList> +#include "tokens.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +struct LexerToken +{ + LexerToken() : token(NOTOKEN), start(-1), end(-1), line(-1), offset(-1) {} + LexerToken(const LexerToken &other) : token(other.token), + start(other.start), + end(other.end), + line(other.line), + offset(other.offset) {} + LexerToken &operator=(const LexerToken &other) { + token = other.token; + start = other.start; + end = other.end; + line = other.line; + offset = other.offset; + return *this; + } + + Token token; + int start; + int end; + int line; + int offset; +}; + +QList<LexerToken> tokenize(const char *text); +void dumpTokens(const char *text, const QList<LexerToken> &tokens); + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/qml/script/qmlbasicscript.cpp b/src/declarative/qml/script/qmlbasicscript.cpp new file mode 100644 index 0000000..4f40016 --- /dev/null +++ b/src/declarative/qml/script/qmlbasicscript.cpp @@ -0,0 +1,923 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qmlbasicscript.h" +#include "qmlbasicscript_p.h" +#include "lexer.h" +#include <QColor> +#include <QDebug> +#include <private/qmlengine_p.h> +#include <private/qmlcontext_p.h> +#include <QStack> +#include <qfxperf.h> +#include <private/qmlrefcount_p.h> + + +QT_BEGIN_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); + +class QmlBasicScriptPrivate +{ +public: + enum Flags { OwnData = 0x00000001 }; + + int size; + int stateSize; + int instructionCount; + int exprLen; + + ScriptInstruction *instructions() const { return (ScriptInstruction *)((char *)this + sizeof(QmlBasicScriptPrivate)); } + + const char *expr() const + { + return (const char *)(instructions() + instructionCount); + } + + const char *data() const + { + return (const char *)(instructions() + instructionCount) + exprLen + 1; + } + + static unsigned int alignRound(int s) + { + if(s % 4) + s += 4 - (s % 4); + return s; + } +}; + +QDebug operator<<(QDebug lhs, const QmlBasicScriptNodeCache &rhs) +{ + switch(rhs.type) { + case QmlBasicScriptNodeCache::Invalid: + lhs << "Invalid"; + break; + case QmlBasicScriptNodeCache::Core: + lhs << "Core" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::Attached: + lhs << "Attached" << rhs.object << rhs.attached; + break; + case QmlBasicScriptNodeCache::Signal: + lhs << "Signal" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::SignalProperty: + lhs << "SignalProperty" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::Explicit: + lhs << "Explicit" << rhs.object; + break; + case QmlBasicScriptNodeCache::Variant: + lhs << "Variant" << rhs.context; + break; + case QmlBasicScriptNodeCache::ScriptValue: + lhs << "ScriptValue" << rhs.context; + break; + } + + return lhs; +} + +void QmlBasicScriptNodeCache::clear() +{ + object = 0; + metaObject = 0; + type = Invalid; +} + +static QVariant toObjectOrVariant(const QVariant &v) +{ + switch(v.type()) { + case QVariant::String: + case QVariant::UInt: + case QVariant::Int: + case 135: + case QVariant::Double: + case QVariant::Color: + case QVariant::Bool: + default: + return v; + case QVariant::UserType: + { + QObject *o = QmlMetaType::toQObject(v); + if (o) + return qVariantFromValue(o); + else + return v; + } + break; + } +} + +static QVariant fetch_value(QObject *o, int idx, int type) +{ + switch(type) { + case QVariant::String: + { + QString val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::UInt: + { + uint val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Int: + { + int val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case 135: + case QVariant::Double: + { + qreal val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Color: + { + QColor val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Bool: + { + bool val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + default: + { + if(QmlMetaType::isObject(type)) { + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + QObject *val = 0; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant::fromValue(val); + } else { + QVariant var = o->metaObject()->property(idx).read(o); + if(QmlMetaType::isObject(var.userType())) { + QObject *obj = 0; + obj = *(QObject **)var.data(); + var = QVariant::fromValue(obj); + } + return var; + } + } + break; + }; +} + +QVariant QmlBasicScriptNodeCache::value(const char *name) const +{ + //QFxPerfTimer<QFxPerf::BasicScriptValue> pt; + switch(type) { + case Invalid: + break; + case Core: + return fetch_value(object, core, coreType); + break; + case Attached: + return qVariantFromValue(static_cast<QObject *>(attached)); + break; + case Signal: + // XXX + Q_ASSERT(!"Not implemented"); + break; + case SignalProperty: + break; + case Explicit: + return qVariantFromValue(object); + break; + case Variant: + return toObjectOrVariant(context->variantProperties[QLatin1String(name)]); + break; + case ScriptValue: + return qVariantFromValue(context->properties[QLatin1String(name)]); + break; + }; + return QVariant(); +} + +struct QmlBasicScriptCompiler +{ + QmlBasicScriptCompiler() + : script(0), stateSize(0), src(0), idx(0) {} + QmlBasicScript *script; + QList<LexerToken> tokens; + int stateSize; + const char *src; + int idx; + + bool compile(); + bool compileExpr(); + + bool parseFetch(); + bool parseName(); + bool parseConstant(); + void skipWhitespace(); + + QByteArray data; + QList<ScriptInstruction> bytecode; + + QByteArray string(int, int); + Token token() const; + bool atEnd() const; + void adv(); + int index() const; +}; + +/*! + \class QmlBasicScript + \brief The QmlBasicScript class provides a fast implementation of a limited subset of JavaScript bindings. + + QmlBasicScript instances are used to accelerate binding. Instead of using + the slower, fully fledged JavaScript engine, many simple bindings can be + evaluated using the QmlBasicScript engine. + + To see if the QmlBasicScript engine can handle a binding, call compile() + and check the return value, or isValid() afterwards. + + To evaluate the binding, the QmlBasicScript instance needs some memory in + which to cache state. This may be allocated by calling newScriptState() + and destroyed by calling deleteScriptState(). The state data is then passed + to the run() method when evaluating the binding. + + To further accelerate binding, QmlBasicScript can return a precompiled + version of itself that can be saved for future use. Call compileData() to + get an opaque pointer to the compiled state, and compileDataSize() for the + size of this data in bytes. This data can be saved and passed to future + instances of the QmlBasicScript constructor. The initial copy of compile + data is owned by the QmlBindScript instance on which compile() was called. +*/ + +/*! + Create a new QmlBasicScript instance. +*/ +QmlBasicScript::QmlBasicScript() +: flags(0), d(0), rc(0) +{ +} + +/*! + Create a new QmlBasicScript instance from saved \a data. + + \a data \b must be data previously acquired from calling compileData() on a + previously created QmlBasicScript instance. Any other data will almost + certainly cause the QmlBasicScript engine to crash. + + \a data must continue to be valid throughout the QmlBasicScript instance + life. It does not assume ownership of the memory. + + If \a owner is set, it is referenced on creation and dereferenced on + destruction of this instance. +*/ +QmlBasicScript::QmlBasicScript(const char *data, QmlRefCount *owner) +: flags(0), d((QmlBasicScriptPrivate *)data), rc(owner) +{ + if(rc) rc->addref(); +} + +/*! + Return the text of the script expression. + */ +QByteArray QmlBasicScript::expression() const +{ + if(!d) + return QByteArray(); + else + return QByteArray(d->expr()); +} + +/*! + Destroy the script instance. +*/ +QmlBasicScript::~QmlBasicScript() +{ + if(flags & QmlBasicScriptPrivate::OwnData) + free(d); + if(rc) rc->release(); + d = 0; + rc = 0; +} + +/*! + Clear this script. The object will then be in its initial state, as though + it were freshly constructed with default constructor. +*/ +void QmlBasicScript::clear() +{ + if(flags & QmlBasicScriptPrivate::OwnData) + free(d); + if(rc) rc->release(); + d = 0; + rc = 0; + flags = 0; +} + +/*! + Return the script state memory for this script instance. This memory should + only be destroyed by calling deleteScriptState(). + */ +void *QmlBasicScript::newScriptState() +{ + if(!d) { + return 0; + } else { + void *rv = ::malloc(d->stateSize * sizeof(QmlBasicScriptNodeCache)); + ::memset(rv, 0, d->stateSize * sizeof(QmlBasicScriptNodeCache)); + return rv; + } +} + +/*! + Delete the \a data previously allocated by newScriptState(). + */ +void QmlBasicScript::deleteScriptState(void *data) +{ + if(!data) return; + Q_ASSERT(d); + clearCache(data); + free(data); +} + +/*! + Dump the script instructions to stderr for debugging. + */ +void QmlBasicScript::dump() +{ + if(!d) + return; + + qWarning() << d->instructionCount << "instructions:"; + const char *data = d->data(); + for(int ii = 0; ii < d->instructionCount; ++ii) { + const ScriptInstruction &instr = d->instructions()[ii]; + + switch(instr.type) { + case ScriptInstruction::Load: + qWarning().nospace() << "LOAD\t\t" << instr.fetch.idx << "\t\t" + << QByteArray(data + instr.fetch.idx); + break; + case ScriptInstruction::Fetch: + qWarning().nospace() << "FETCH\t\t" << instr.fetch.idx << "\t\t" + << QByteArray(data + instr.fetch.idx); + break; + case ScriptInstruction::Add: + qWarning().nospace() << "ADD"; + break; + case ScriptInstruction::Subtract: + qWarning().nospace() << "SUBTRACT"; + break; + case ScriptInstruction::Multiply: + qWarning().nospace() << "MULTIPLY"; + break; + case ScriptInstruction::Equals: + qWarning().nospace() << "EQUALS"; + break; + case ScriptInstruction::Int: + qWarning().nospace() << "INT\t\t" << instr.integer.value; + break; + case ScriptInstruction::Bool: + qWarning().nospace() << "BOOL\t\t" << instr.boolean.value; + break; + default: + qWarning().nospace() << "UNKNOWN"; + break; + } + } +} + +/*! + Return true if this is a valid script binding, otherwise returns false. + */ +bool QmlBasicScript::isValid() const +{ + return d != 0; +} + +/*! + Compile \a src and return true if the compilation is successful, otherwise + returns false. + */ +bool QmlBasicScript::compile(const QByteArray &src) +{ + bool rv = compile(src.constData()); + return rv; +} + +/*! + \overload + + Compile \a src and return true if the compilation is successful, otherwise + returns false. + */ +bool QmlBasicScript::compile(const char *src) +{ + if(!src) return false; + + QmlBasicScriptCompiler bsc; + bsc.script = this; + bsc.tokens = tokenize(src); + bsc.src = src; + // dumpTokens(src, bsc.tokens); + + if(d) { + if(flags & QmlBasicScriptPrivate::OwnData) + free(d); + d = 0; + flags = 0; + } + + if(bsc.compile()) { + int len = ::strlen(src); + flags = QmlBasicScriptPrivate::OwnData; + int size = sizeof(QmlBasicScriptPrivate) + + bsc.bytecode.count() * sizeof(ScriptInstruction) + + QmlBasicScriptPrivate::alignRound(bsc.data.count() + len + 1); + d = (QmlBasicScriptPrivate *) malloc(size); + d->size = size; + d->stateSize = bsc.stateSize; + d->instructionCount = bsc.bytecode.count(); + d->exprLen = len; + ::memcpy((char *)d->expr(), src, len + 1); + for(int ii = 0; ii < d->instructionCount; ++ii) + d->instructions()[ii] = bsc.bytecode.at(ii); + ::memcpy((char *)d->data(), bsc.data.constData(), bsc.data.count()); + } + + return d != 0; +} + +void QmlBasicScriptCompiler::skipWhitespace() +{ + while(idx < tokens.count() && tokens.at(idx).token == WHITESPACE) + ++idx; +} + +bool QmlBasicScriptCompiler::compile() +{ + if(!compileExpr()) + return false; + + skipWhitespace(); + + if(atEnd()) + return true; + + int t = token(); + if(t != AND) + return false; + + adv(); + skipWhitespace(); + if(!compileExpr()) + return false; + + ScriptInstruction instr; + instr.type = ScriptInstruction::And; + bytecode.append(instr); + + skipWhitespace(); + + return atEnd(); +} + +bool QmlBasicScriptCompiler::compileExpr() +{ + /* + EXPRESSION := <NAME><OPERATOR>[<CONSTANT>|<NAME>] + */ + + if(!parseName()) + return false; + + skipWhitespace(); + + if(atEnd()) + return true; + + int t = token(); + switch(t) { + case PLUS: + case MINUS: + /* + case LANGLE: + case RANGLE: + */ + case STAR: + case EQUALS: + break; + default: + return true; + } + adv(); + + skipWhitespace(); + + if(!parseConstant() && + !parseName()) + return false; + + ScriptInstruction instr; + switch(t) { + case PLUS: + instr.type = ScriptInstruction::Add; + break; + case MINUS: + instr.type = ScriptInstruction::Subtract; + break; + case STAR: + instr.type = ScriptInstruction::Multiply; + break; + case EQUALS: + instr.type = ScriptInstruction::Equals; + break; + default: + break; + } + bytecode.append(instr); + + skipWhitespace(); + + return true; +} + +bool QmlBasicScriptCompiler::parseName() +{ + skipWhitespace(); + + bool named = false; + bool seenchar = false; + bool seendot = false; + int namestart = -1; + bool pushed = false; + while(!atEnd()) { + int t = token(); + if(t == CHARACTER) { + named = true; + seendot = false; + seenchar = true; + namestart = index(); + adv(); + } else if(t == DIGIT) { + if(!seenchar) break; + adv(); + } else if(t == DOT) { + seendot = true; + if(namestart == -1) + break; + + seenchar = false; + QByteArray name = string(namestart, index() - 1); + int nref = data.count(); + data.append(name); + data.append('\0'); + ScriptInstruction instr; + if(pushed) + instr.type = ScriptInstruction::Fetch; + else + instr.type = ScriptInstruction::Load; + pushed = true; + instr.fetch.idx = nref; + bytecode.append(instr); + ++stateSize; + namestart = -1; + adv(); + } else { + break; + } + } + + if(namestart != -1) { + QByteArray name = string(namestart, index() - 1); + int nref = data.count(); + data.append(name); + data.append('\0'); + ScriptInstruction instr; + if(pushed) + instr.type = ScriptInstruction::Fetch; + else + instr.type = ScriptInstruction::Load; + pushed = true; + instr.fetch.idx = nref; + bytecode.append(instr); + ++stateSize; + } + + if(seendot) + return false; + else + return named; +} + +bool QmlBasicScriptCompiler::parseConstant() +{ + switch(token()) { + case DIGIT: + { + ScriptInstruction instr; + instr.type = ScriptInstruction::Int; + instr.integer.value = string(index(), index()).toUInt(); + bytecode.append(instr); + adv(); + } + break; + case TOKEN_TRUE: + case TOKEN_FALSE: + { + ScriptInstruction instr; + instr.type = ScriptInstruction::Bool; + instr.boolean.value = (token() == TOKEN_TRUE); + bytecode.append(instr); + adv(); + } + break; + + default: + return false; + } + + return true; +} + +bool QmlBasicScriptCompiler::atEnd() const +{ + return idx >= tokens.count(); +} + +Token QmlBasicScriptCompiler::token() const +{ + return tokens.at(idx).token; +} + +void QmlBasicScriptCompiler::adv() +{ + ++idx; +} + +int QmlBasicScriptCompiler::index() const +{ + return idx; +} + +QByteArray QmlBasicScriptCompiler::string(int from, int to) +{ + QByteArray rv; + for(int ii = from; ii <= to; ++ii) { + const LexerToken &token = tokens.at(ii); + rv.append(QByteArray(src + token.start, token.end - token.start + 1)); + } + return rv; +} + +/*! + \internal +*/ +void QmlBasicScript::clearCache(void *voidCache) +{ + QmlBasicScriptNodeCache *dataCache = + reinterpret_cast<QmlBasicScriptNodeCache *>(voidCache); + + for(int ii = 0; ii < d->stateSize; ++ii) { + if(!dataCache[ii].isCore() && !dataCache[ii].isExplicit() && + dataCache[ii].object) { + QMetaObject::removeGuard(&dataCache[ii].object); + dataCache[ii].object = 0; + } + dataCache[ii].clear(); + } +} + +void QmlBasicScript::guard(QmlBasicScriptNodeCache &n) +{ + if(n.object) { + if(n.isExplicit()) { + } else if(n.isCore()) { + n.metaObject = + n.object->metaObject(); + } else { + QMetaObject::addGuard(&n.object); + } + } +} + +bool QmlBasicScript::valid(QmlBasicScriptNodeCache &n, QObject *obj) +{ + return n.object == obj && + (!n.isCore() || obj->metaObject() == n.metaObject); +} + + +/*! + \enum QmlBasicScript::CacheState + \value NoChange The query has not change. Any previous monitoring is still + valid. + \value Incremental The query has been incrementally changed. Any previous + monitoring is still valid, but needs to have the fresh properties added to + it. + \value Reset The entire query has been reset from the beginning. Any previous + monitoring is now invalid. +*/ + +/*! + Run the script in \a context and return the result. \a voidCache should + contain state memory previously acquired from newScript. + */ +QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *cached) +{ + if(!isValid()) + return QVariant(); + + QmlBasicScriptNodeCache *dataCache = + reinterpret_cast<QmlBasicScriptNodeCache *>(voidCache); + int dataCacheItem; + QStack<QVariant> stack; + + bool resetting = false; + bool hasReset = false; + + const char *data = d->data(); + + if(dataCache[0].type == QmlBasicScriptNodeCache::Invalid) { + resetting = true; + hasReset = true; + } + + CacheState state = NoChange; + + dataCacheItem = 0; + for(int idx = 0; idx < d->instructionCount; ++idx) { + const ScriptInstruction &instr = d->instructions()[idx]; + + switch(instr.type) { + case ScriptInstruction::Load: // either an object or a property + case ScriptInstruction::Fetch: // can only be a property + { + const char *id = data + instr.fetch.idx; + QmlBasicScriptNodeCache &n = dataCache[dataCacheItem]; + + if(instr.type == ScriptInstruction::Load) { + + if(n.type == QmlBasicScriptNodeCache::Invalid) { + context->engine()->d_func()->loadCache(n, QLatin1String(id), static_cast<QmlContextPrivate*>(context->d_ptr)); + state = Incremental; + } + + } else { // instr.type == ScriptInstruction::Fetch + + QVariant o = stack.pop(); + QObject *obj = qvariant_cast<QObject *>(o); + if(!obj) { + if(n.type == QmlBasicScriptNodeCache::Invalid) { + if(scriptWarnings()) + qWarning() << "QmlBasicScript: Unable to convert" << o; + *cached = state; + return QVariant(); + } else { + clearCache(dataCache); + *cached = Reset; + CacheState dummy; + return run(context, voidCache, &dummy); + } + } else if(n.type == QmlBasicScriptNodeCache::Invalid) { + context->engine()->d_func()->fetchCache(n, QLatin1String(id), obj); + guard(n); + state = Incremental; + } else if(!valid(n, obj)) { + clearCache(dataCache); + *cached = Reset; + CacheState dummy; + return run(context, voidCache, &dummy); + } + + } + + QVariant var = n.value(id); + stack.push(var); + ++dataCacheItem; + } + break; + case ScriptInstruction::Int: + stack.push(QVariant(instr.integer.value)); + break; + case ScriptInstruction::Bool: + stack.push(QVariant(instr.boolean.value)); + break; + case ScriptInstruction::Add: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toDouble() + lhs.toDouble()); + } + break; + case ScriptInstruction::Subtract: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(lhs.toDouble() - rhs.toDouble()); + } + break; + case ScriptInstruction::Multiply: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toDouble() * lhs.toDouble()); + } + break; + case ScriptInstruction::Equals: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs == lhs); + } + break; + case ScriptInstruction::And: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toBool() && lhs.toBool()); + } + break; + default: + break; + } + } + + *cached = state; + + if(stack.isEmpty()) + return QVariant(); + else + return stack.top(); +} + +/*! + Return a pointer to the script's compile data, or null if there is no data. + */ +const char *QmlBasicScript::compileData() const +{ + return (const char *)d; +} + +/*! + Return the size of the script's compile data, or zero if there is no data. + The size will always be a multiple of 4. + */ +unsigned int QmlBasicScript::compileDataSize() const +{ + if(d) + return d->size; + else + return 0; +} + +bool QmlBasicScript::isSingleLoad() const +{ + if(!d) + return false; + + return d->instructionCount == 1 && + d->instructions()[0].type == ScriptInstruction::Load; +} + +QByteArray QmlBasicScript::singleLoadTarget() const +{ + if(!isSingleLoad()) + return QByteArray(); + + // We know there is one instruction and it is a load + return QByteArray(d->data() + d->instructions()[0].fetch.idx); +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/script/qmlbasicscript.h b/src/declarative/qml/script/qmlbasicscript.h new file mode 100644 index 0000000..d465f04 --- /dev/null +++ b/src/declarative/qml/script/qmlbasicscript.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBASICSCRIPT_H +#define QMLBASICSCRIPT_H + +#include "instructions.h" +#include <QList> +#include <QByteArray> +#include "lexer.h" +#include <QVariant> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QmlRefCount; +class QmlContext; +class QmlBasicScriptPrivate; +class QmlBasicScriptNodeCache; +class QmlBasicScript +{ +public: + QmlBasicScript(); + QmlBasicScript(const char *, QmlRefCount * = 0); + ~QmlBasicScript(); + + // Always 4-byte aligned + const char *compileData() const; + unsigned int compileDataSize() const; + + QByteArray expression() const; + + bool compile(const QByteArray &); + bool compile(const char *); + bool isValid() const; + + void clear(); + + void dump(); + void *newScriptState(); + void deleteScriptState(void *); + + enum CacheState { NoChange, Incremental, Reset }; + QVariant run(QmlContext *, void *, CacheState *); + + // Optimization opportunities + bool isSingleLoad() const; + QByteArray singleLoadTarget() const; + +private: + int flags; + QmlBasicScriptPrivate *d; + QmlRefCount *rc; + + void clearCache(void *); + void guard(QmlBasicScriptNodeCache &); + bool valid(QmlBasicScriptNodeCache &, QObject *); +}; + +#endif // QMLBASICSCRIPT_H + + +QT_END_NAMESPACE + +QT_END_HEADER diff --git a/src/declarative/qml/script/qmlbasicscript_p.h b/src/declarative/qml/script/qmlbasicscript_p.h new file mode 100644 index 0000000..bcb7d00 --- /dev/null +++ b/src/declarative/qml/script/qmlbasicscript_p.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBASICSCRIPT_P_H +#define QMLBASICSCRIPT_P_H + +QT_BEGIN_NAMESPACE + +class QObject; +class QmlContextPrivate; +class QDebug; +class QByteArray; + +class QmlBasicScriptNodeCache +{ +public: + QObject *object; + const QMetaObject *metaObject; + enum { Invalid, + Core, + Attached, + Signal, + SignalProperty, + Explicit, + Variant, + ScriptValue } type; + union { + int core; + QObject *attached; + QmlContextPrivate *context; + }; + int coreType; + + bool isCore() const { return type == Core; } + bool isExplicit() const { return type == Explicit; } + void clear(); + QVariant value(const char *) const; +}; + +QDebug operator<<(QDebug, const QmlBasicScriptNodeCache &); + +#endif // QMLBASICSCRIPT_P_H + +QT_END_NAMESPACE diff --git a/src/declarative/qml/script/script.pri b/src/declarative/qml/script/script.pri new file mode 100644 index 0000000..6c43efe --- /dev/null +++ b/src/declarative/qml/script/script.pri @@ -0,0 +1,11 @@ +SOURCES += \ + qml/script/tokens.cpp \ + qml/script/lexer.cpp \ + qml/script/qmlbasicscript.cpp + +HEADERS += \ + qml/script/tokens.h \ + qml/script/lexer.h \ + qml/script/instructions.h \ + qml/script/qmlbasicscript.h \ + qml/script/qmlbasicscript_p.h diff --git a/src/declarative/qml/script/tokens.cpp b/src/declarative/qml/script/tokens.cpp new file mode 100644 index 0000000..51b46f0 --- /dev/null +++ b/src/declarative/qml/script/tokens.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "tokens.h" + + +/*! + \relates <tokens.h> + Returns a string representation of token \a tok. +*/ +const char *tokenToString(Token tok) +{ + switch(tok) { +#define CASE(X) case X: return #X; + CASE(NOTOKEN) + CASE(INCOMPLETE) + CASE(WHITESPACE) + CASE(LANGLE) + CASE(RANGLE) + CASE(PLUS) + CASE(MINUS) + CASE(STAR) + CASE(EQUALS) + CASE(DOT) + CASE(CHARACTER) + CASE(DIGIT) + CASE(OTHER) + CASE(AND) + case TOKEN_TRUE: + return "TRUE"; + case TOKEN_FALSE: + return "FALSE"; +#undef CASE + } + return 0; +} + diff --git a/src/declarative/qml/script/tokens.h b/src/declarative/qml/script/tokens.h new file mode 100644 index 0000000..753e40c --- /dev/null +++ b/src/declarative/qml/script/tokens.h @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef TOKENS_H +#define TOKENS_H + +enum Token { + // Lexer tokens + NOTOKEN, + INCOMPLETE, + WHITESPACE, + LANGLE, + RANGLE, + PLUS, + MINUS, + STAR, + EQUALS, + AND, + DOT, + CHARACTER, + DIGIT, + TOKEN_TRUE, + TOKEN_FALSE, + OTHER +}; + +const char *tokenToString(Token); + +#endif |