Bind each QML document after parsing. Link them before use.

Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
Christian Kamm
2010-02-02 15:55:17 +01:00
parent e7a330f92a
commit 03fa188b41
8 changed files with 321 additions and 315 deletions

View File

@@ -121,76 +121,27 @@ public:
}
};
class ProcessSourceElements: protected AST::Visitor
{
Interpreter::Engine *_interp;
public:
ProcessSourceElements(Interpreter::Engine *interp)
: _interp(interp),
typeOfExpression(interp)
{
}
void operator()(AST::Node *node)
{
if (node)
node->accept(this);
}
protected:
using AST::Visitor::visit;
virtual bool visit(FunctionDeclaration *ast)
{
if (ast->name)
_interp->globalObject()->setProperty(ast->name->asString(), new ASTFunctionValue(ast, _interp));
return false;
}
virtual bool visit(VariableDeclaration *ast)
{
if (ast->name) {
const Value *value = _interp->undefinedValue();
if (ast->expression)
value = typeOfExpression(ast->expression, _interp->globalObject());
_interp->globalObject()->setProperty(ast->name->asString(), value);
}
return false;
}
Check typeOfExpression;
};
} // end of anonymous namespace
Bind::Bind(Document::Ptr doc, Interpreter::Engine *interp)
Bind::Bind(Document *doc)
: _doc(doc),
_interp(interp),
_currentObjectValue(0),
_typeEnvironment(0),
_idEnvironment(0),
_functionEnvironment(0),
_rootObjectValue(0)
{
if (_doc && _doc->qmlProgram() != 0) {
UiProgram *program = _doc->qmlProgram();
if (!_doc)
return;
_currentObjectValue = 0;
_typeEnvironment = _interp->newObject(/*prototype =*/ 0);
_idEnvironment = _interp->newObject(/*prototype =*/ 0);
_functionEnvironment = _interp->newObject(/*prototype =*/ 0);
_rootObjectValue = 0;
_qmlObjectDefinitions.clear();
_qmlObjectBindings.clear();
accept(program);
if (_doc->qmlProgram()) {
_idEnvironment = _interp.newObject(/*prototype =*/ 0);
_functionEnvironment = _interp.newObject(/*prototype =*/ 0);
} else if (_doc->jsProgram()) {
_currentObjectValue = _interp.globalObject();
_rootObjectValue = _interp.globalObject();
}
accept(_doc->ast());
}
Bind::~Bind()
@@ -214,77 +165,6 @@ ObjectValue *Bind::switchObjectValue(ObjectValue *newObjectValue)
return oldObjectValue;
}
ObjectValue *Bind::scopeChainAt(Document::Ptr currentDocument, const Snapshot &snapshot,
Interpreter::Engine *interp, AST::UiObjectMember *currentObject)
{
Bind *currentBind = 0;
QList<Bind *> binds;
QSet<QString> processed;
QStringList todo;
QMultiHash<QString, Document::Ptr> documentByPath;
foreach (Document::Ptr doc, snapshot)
documentByPath.insert(doc->path(), doc);
todo.append(currentDocument->path());
// Bind the reachable documents.
while (! todo.isEmpty()) {
const QString path = todo.takeFirst();
if (processed.contains(path))
continue;
processed.insert(path);
QStringList localImports;
foreach (Document::Ptr doc, documentByPath.values(path)) {
Bind *newBind = new Bind(doc, interp);
binds += newBind;
localImports += newBind->localImports();
if (doc == currentDocument)
currentBind = newBind;
}
localImports.removeDuplicates();
todo += localImports;
}
LinkImports linkImports;
Link link;
// link the import directives
linkImports(binds);
// link the scripts
QStringList includedScriptFiles;
foreach (Bind *bind, binds)
includedScriptFiles += bind->includedScripts();
includedScriptFiles.removeDuplicates();
ProcessSourceElements processSourceElements(interp);
foreach (const QString &scriptFile, includedScriptFiles) {
if (Document::Ptr scriptDoc = snapshot.document(scriptFile)) {
if (AST::Program *program = scriptDoc->jsProgram()) {
processSourceElements(program);
}
}
}
ObjectValue *scope = interp->globalObject();
if (currentBind)
scope = link(binds, currentBind, currentObject);
qDeleteAll(binds);
return scope;
}
QString Bind::toString(UiQualifiedId *qualifiedId, QChar delimiter)
{
QString result;
@@ -350,7 +230,7 @@ ObjectValue *Bind::bindObject(UiQualifiedId *qualifiedTypeNameId, UiObjectInitia
}
// normal component instance
ASTObjectValue *objectValue = new ASTObjectValue(qualifiedTypeNameId, initializer, _interp);
ASTObjectValue *objectValue = new ASTObjectValue(qualifiedTypeNameId, initializer, &_interp);
parentObjectValue = switchObjectValue(objectValue);
if (parentObjectValue)
@@ -368,64 +248,9 @@ void Bind::accept(Node *node)
Node::accept(node, this);
}
/*
import Qt 4.6
import Qt 4.6 as Xxx
(import com.nokia.qt is the same as the ones above)
import "content"
import "content" as Xxx
import "content" 4.6
import "content" 4.6 as Xxx
import "http://www.ovi.com/" as Ovi
*/
// ### TODO: Move to LinkImports
bool Bind::visit(UiImport *ast)
{
if (! (ast->importUri || ast->fileName))
return false; // nothing to do.
ObjectValue *namespaceObject = 0;
if (ast->asToken.isValid()) { // with namespace we insert an object in the type env. to hold the imported types
if (!ast->importId)
return false; // this should never happen, but better be safe than sorry
namespaceObject = _interp->newObject(/*prototype */ 0);
_typeEnvironment->setProperty(ast->importId->asString(), namespaceObject);
} else { // without namespace we insert all types directly into the type env.
namespaceObject = _typeEnvironment;
}
// look at files first
// else try the metaobject system
if (ast->importUri) {
const QString package = toString(ast->importUri, '/');
int majorVersion = -1; // ### TODO: Check these magic version numbers
int minorVersion = -1; // ### TODO: Check these magic version numbers
if (ast->versionToken.isValid()) {
const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
const int dotIdx = versionString.indexOf(QLatin1Char('.'));
if (dotIdx == -1) {
// only major (which is probably invalid, but let's handle it anyway)
majorVersion = versionString.toInt();
minorVersion = 0; // ### TODO: Check with magic version numbers above
} else {
majorVersion = versionString.left(dotIdx).toInt();
minorVersion = versionString.mid(dotIdx + 1).toInt();
}
}
#ifndef NO_DECLARATIVE_BACKEND
foreach (QmlObjectValue *object, _interp->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
namespaceObject->setProperty(object->qmlTypeName(), object);
}
#endif // NO_DECLARATIVE_BACKEND
} else if (ast->fileName) {
if (ast->fileName) {
QString path = _doc->path();
path += QLatin1Char('/');
path += ast->fileName->asString();
@@ -488,7 +313,7 @@ bool Bind::visit(FunctionDeclaration *ast)
if (_currentObjectValue->property(ast->name->asString()))
return false;
ASTFunctionValue *function = new ASTFunctionValue(ast, _interp);
ASTFunctionValue *function = new ASTFunctionValue(ast, &_interp);
_currentObjectValue->setProperty(ast->name->asString(), function);
return false; // ### eventually want to visit function bodies
}