From 2d5b8207b4500945d921fb1ef8b608725827f5e0 Mon Sep 17 00:00:00 2001 From: Anders Bakken Date: Thu, 28 Mar 2013 00:42:24 -0700 Subject: [PATCH] I still have some bugs with scoping but it's kinda useful, even for larger js-files. --- src/JSParser.cpp | 64 +++++++++++++++++++++++++++++++++++++++--------- src/JSParser.h | 13 ++++++++-- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/JSParser.cpp b/src/JSParser.cpp index a4a1c1951..52f567ef8 100644 --- a/src/JSParser.cpp +++ b/src/JSParser.cpp @@ -26,6 +26,8 @@ v8::Handle toJSON(v8::Handle obj) template static v8::Handle get(v8::Handle object, v8::Handle property) { + if (object.IsEmpty() || !object->IsObject()) + return v8::Handle(); v8::HandleScope scope; v8::Handle prop(object->Get(property)); if (prop.IsEmpty() || prop->IsNull() || prop->IsUndefined()) { @@ -57,6 +59,8 @@ static v8::Persistent getPersistent(v8::Handle object, const char template static v8::Handle get(v8::Handle object, int index) { + if (object.IsEmpty() || !object->IsArray()) + return v8::Handle(); v8::HandleScope scope; v8::Handle prop = object->Get(index); if (prop.IsEmpty() || prop->IsNull() || prop->IsUndefined()) { @@ -68,7 +72,7 @@ static v8::Handle get(v8::Handle object, int index) static inline bool operator==(v8::Handle l, const char *r) { - error() << "comparing" << (l.IsEmpty() ? "empty" : toCString(l)) << r; + // error() << "comparing" << (l.IsEmpty() ? "empty" : toCString(l)) << r; return l.IsEmpty() ? (!r || !strlen(r)) : !strcmp(toCString(l), r); } @@ -167,7 +171,7 @@ bool JSParser::parse(const Path &path, const String &contents, SymbolMap *symbol if (json) *json = toCString(toJSON(result)); mScope.append(Map()); - recurseObject(get(result->ToObject(), "body"), "body"); + recurseObject(get(result->ToObject(), "body"), "body", None); mScope.removeLast(); } else if (errors) { *errors = "Failed to parse"; @@ -183,7 +187,9 @@ bool JSParser::parse(const Path &path, const String &contents, SymbolMap *symbol return true; } -void JSParser::handleIdentifier(v8::Handle object, bool function) +int indent = 0; + +void JSParser::handleIdentifier(v8::Handle object, unsigned flags) { v8::Handle name = get(object, "name"); v8::Handle range = get(object, "range"); @@ -194,8 +200,7 @@ void JSParser::handleIdentifier(v8::Handle object, bool function) const Location loc(mFileId, offset); c.symbolName = String(toCString(name), name->Length()); c.symbolLength = length; - error() << "Got function" << c.symbolName << function; - if (function) { + if (flags & FunctionDeclaration) { c.kind = CursorInfo::JSFunction; } else { c.kind = CursorInfo::JSVariable; @@ -220,47 +225,84 @@ void JSParser::handleIdentifier(v8::Handle object, bool function) for (int i=mParents.size(); i>=0; --i) { if (i < mParents.size()) { c.symbolName.prepend(mParents.at(i) + '.'); - } else if (c.kind != CursorInfo::JSReference) { - mScope.last()[c.symbolName] = offset; + } else { + if (c.kind != CursorInfo::JSReference) + mScope.last()[c.symbolName] = offset; + if (flags & AddToParents) + mParents.append(c.symbolName); } if (c.kind != CursorInfo::JSReference) { if (mSymbolNames) (*mSymbolNames)[c.symbolName].insert(loc); } } + for (int i=0; i object, const char *name) +bool JSParser::recurseObject(v8::Handle object, const char *name, unsigned flags) { if (object.IsEmpty()) return false; + for (int i=0; i type = get(object, "type"); + printf("recursing %s%s\n", name ? name : "(unnamed)", + !type.IsEmpty() && type->IsString() ? String::format<64>(" type: %s", toCString(type)).constData() : ""); + + ++indent; bool popScope = false; if (name && !strcmp(name, "body")) { popScope = true; + // error() << "adding a scope"; mScope.append(Map()); } if (object->IsArray()) { v8::Handle array = v8::Handle::Cast(object); for (unsigned i=0; iLength(); ++i) { - recurseObject(get(array, i), 0); + recurseObject(get(array, i), 0, flags); } } else if (object->IsObject()) { v8::Handle props = object->GetOwnPropertyNames(); assert(!props.IsEmpty()); + bool addToParent = false; + v8::Handle objectType = get(object, "type"); + if (objectType == "AssignmentExpression") { + flags |= AssignmentExpression; + } else if (objectType == "VariableDeclarator") { + flags |= VariableDeclarator; + } + for (unsigned i=0; iLength(); ++i) { v8::Handle prop = get(props, i); v8::Handle sub = get(object, prop); if (!sub.IsEmpty() && sub->IsObject()) { if (get(sub, "type") == "Identifier") { - handleIdentifier(sub, get(object, "type") == "FunctionDeclaration"); + unsigned identifierFlags = None; + if (objectType == "FunctionDeclaration") + identifierFlags |= FunctionDeclaration; + if ((flags & AssignmentExpression && prop == "object") || (flags & VariableDeclarator && prop == "id")) { + identifierFlags |= AddToParents; + addToParent = true; + } + handleIdentifier(sub, identifierFlags); } else { - recurseObject(sub, toCString(prop)); + recurseObject(sub, toCString(prop), flags); } } } + if (addToParent) { + assert(!mParents.isEmpty()); + mParents.removeLast(); + } } if (popScope) mScope.removeLast(); + --indent; + return true; } diff --git a/src/JSParser.h b/src/JSParser.h index 55f7bf137..3589f2ac1 100644 --- a/src/JSParser.h +++ b/src/JSParser.h @@ -23,8 +23,17 @@ class JSParser String *errors, String *json = 0); private: - bool recurseObject(v8::Handle object, const char *name); - void handleIdentifier(v8::Handle object, bool function); + enum { None = 0x0 }; + enum RecurseFlag { + AssignmentExpression = 0x1, + VariableDeclarator = 0x2 + }; + bool recurseObject(v8::Handle object, const char *name, unsigned flags); + enum IdentifierFlag { + FunctionDeclaration = 0x1, + AddToParents = 0x2 + }; + void handleIdentifier(v8::Handle object, unsigned flags); v8::Persistent mContext; v8::Persistent mEsprima;