]> git.saurik.com Git - cycript.git/blobdiff - Replace.cpp
Check for APR and GNU make.
[cycript.git] / Replace.cpp
index d44374e3f0d1d5575905b473e872a72841dad5a1..c06c2a514e91711346494fab13feb64c38c579b5 100644 (file)
@@ -338,8 +338,9 @@ void CYFunction::Replace_(CYContext &context, bool outer) {
     if (outer)
         Inject(context);
 
-    parent_ = context.scope_;
-    context.scope_ = this;
+    CYScope scope;
+    scope.parent_ = context.scope_;
+    context.scope_ = &scope;
 
     if (!outer && name_ != NULL)
         Inject(context);
@@ -347,8 +348,8 @@ void CYFunction::Replace_(CYContext &context, bool outer) {
     parameters_->Replace(context);
     code_.Replace(context);
 
-    context.scope_ = parent_;
-    Scope(context, code_.statements_);
+    context.scope_ = scope.parent_;
+    scope.Scope(context, code_.statements_);
 }
 
 CYExpression *CYFunctionExpression::Replace(CYContext &context) {
@@ -368,8 +369,9 @@ CYStatement *CYFunctionStatement::Replace(CYContext &context) {
 }
 
 CYIdentifier *CYIdentifier::Replace(CYContext &context) {
-    if (replace_ == NULL)
-        replace_ = context.scope_->Lookup(context, this);
+    if (replace_ != NULL && replace_ != this)
+        return replace_->Replace(context);
+    replace_ = context.scope_->Lookup(context, this);
     return replace_;
 }
 
@@ -456,29 +458,48 @@ CYExpression *CYPrefix::Replace(CYContext &context) {
     return this;
 }
 
+// XXX: this is evil evil black magic. don't ask, don't tell... don't believe!
 #define MappingSet "0etnirsoalfucdphmgyvbxTwSNECAFjDLkMOIBPqzRH$_WXUVGYKQJZ"
+//#define MappingSet "0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_"
+
+namespace {
+    struct IdentifierUsageLess :
+        std::binary_function<CYIdentifier *, CYIdentifier *, bool>
+    {
+        _finline bool operator ()(CYIdentifier *lhs, CYIdentifier *rhs) const {
+            if (lhs->usage_ != rhs->usage_)
+                return lhs->usage_ > rhs->usage_;
+            return lhs < rhs;
+        }
+    };
 
-void CYProgram::Replace(CYContext &context) {
-    parent_ = context.scope_;
-    CYProgram *program(context.program_);
-
-    context.scope_ = this;
-    context.program_ = this;
+    typedef std::set<CYIdentifier *, IdentifierUsageLess> IdentifierUsages;
+}
 
+void CYProgram::Replace(CYContext &context) {
+    CYScope scope;
+    scope.parent_ = context.scope_;
+    context.scope_ = &scope;
     statements_ = statements_->ReplaceAll(context);
-
-    context.scope_ = parent_;
-    context.program_ = program;
-    Scope(context, statements_);
+    context.scope_ = scope.parent_;
+    scope.Scope(context, statements_);
 
     size_t offset(0);
 
     CYCStringSet external;
-    for (CYIdentifierValueSet::const_iterator i(identifiers_.begin()); i != identifiers_.end(); ++i)
+    for (CYIdentifierValueSet::const_iterator i(scope.identifiers_.begin()); i != scope.identifiers_.end(); ++i)
         external.insert((*i)->Word());
 
+    IdentifierUsages usages;
+
+    if (offset < context.rename_.size())
+        for (CYIdentifier *i(context.rename_[offset].identifier_); i != NULL; i = i->next_)
+             usages.insert(i);
+
     // XXX: totalling the probable occurrences and sorting by them would improve the result
-    for (CYIdentifierAddressVector::const_iterator i(rename_.begin()); i != rename_.end(); ++i, ++offset) {
+    for (CYIdentifierUsageVector::const_iterator i(context.rename_.begin()); i != context.rename_.end(); ++i, ++offset) {
+        //std::cout << *i << ":" << (*i)->offset_ << std::endl;
+
         const char *name;
 
         if (context.options_.verbose_)
@@ -505,7 +526,7 @@ void CYProgram::Replace(CYContext &context) {
             // XXX: at some point, this could become a keyword
         }
 
-        for (CYIdentifier *identifier(*i); identifier != NULL; identifier = identifier->next_)
+        for (CYIdentifier *identifier(i->identifier_); identifier != NULL; identifier = identifier->next_)
             identifier->Set(name);
     }
 }
@@ -530,45 +551,81 @@ CYIdentifier *CYScope::Lookup(CYContext &context, CYIdentifier *identifier) {
 }
 
 void CYScope::Merge(CYContext &context, CYIdentifier *identifier) {
-    std::pair<CYIdentifierAddressSet::iterator, bool> insert(identifiers_.insert(identifier));
+    std::pair<CYIdentifierValueSet::iterator, bool> insert(identifiers_.insert(identifier));
     if (!insert.second) {
         if ((*insert.first)->offset_ < identifier->offset_)
             (*insert.first)->offset_ = identifier->offset_;
         identifier->replace_ = *insert.first;
+        (*insert.first)->usage_ += identifier->usage_ + 1;
     }
 }
 
+namespace {
+    struct IdentifierOffset {
+        size_t offset_;
+        CYIdentifierFlags flags_;
+        size_t usage_;
+        CYIdentifier *identifier_;
+
+        IdentifierOffset(CYIdentifier *identifier, CYIdentifierFlags flags) :
+            offset_(identifier->offset_),
+            flags_(flags),
+            usage_(identifier->usage_),
+            identifier_(identifier)
+        {
+        }
+    };
+
+    struct IdentifierOffsetLess :
+        std::binary_function<const IdentifierOffset &, const IdentifierOffset &, bool>
+    {
+        _finline bool operator ()(const IdentifierOffset &lhs, const IdentifierOffset &rhs) const {
+            if (lhs.offset_ != rhs.offset_)
+                return lhs.offset_ < rhs.offset_;
+            if (lhs.flags_ != rhs.flags_)
+                return lhs.flags_ < rhs.flags_;
+            /*if (lhs.usage_ != rhs.usage_)
+                return lhs.usage_ < rhs.usage_;*/
+            return lhs.identifier_ < rhs.identifier_;
+        }
+    };
+
+    typedef std::set<IdentifierOffset, IdentifierOffsetLess> IdentifierOffsets;
+}
+
 void CYScope::Scope(CYContext &context, CYStatement *&statements) {
+    if (parent_ == NULL)
+        return;
+
     CYDeclarations *last(NULL), *curr(NULL);
-    CYProgram *program(context.program_);
 
-    typedef std::multimap<size_t, CYIdentifier *> IdentifierOffsetMap;
-    IdentifierOffsetMap offsetted;
+    IdentifierOffsets offsets;
 
-    // XXX: we don't want to do this in order, we want to sort it by probable occurrence
-    for (CYIdentifierAddressFlagsMap::const_iterator i(internal_.begin()); i != internal_.end(); ++i) {
-        if (program != NULL && i->second != CYIdentifierMagic)
-            offsetted.insert(IdentifierOffsetMap::value_type(i->first->offset_, i->first));
-        if (i->second == CYIdentifierVariable) {
-            CYDeclarations *next($ CYDeclarations($ CYDeclaration(i->first)));
+    for (CYIdentifierAddressFlagsMap::const_iterator i(internal_.begin()); i != internal_.end(); ++i)
+        if (i->second != CYIdentifierMagic)
+            offsets.insert(IdentifierOffset(i->first, i->second));
+
+    size_t offset(0);
+
+    for (IdentifierOffsets::const_iterator i(offsets.begin()); i != offsets.end(); ++i) {
+        if (i->flags_ == CYIdentifierVariable) {
+            CYDeclarations *next($ CYDeclarations($ CYDeclaration(i->identifier_)));
             if (last == NULL)
                 last = next;
             if (curr != NULL)
                 curr->SetNext(next);
             curr = next;
         }
-    }
 
-    size_t offset(0);
+        if (offset < i->offset_)
+            offset = i->offset_;
+        if (context.rename_.size() <= offset)
+            context.rename_.resize(offset + 1);
 
-    for (IdentifierOffsetMap::const_iterator i(offsetted.begin()); i != offsetted.end(); ++i) {
-        if (offset < i->first)
-            offset = i->first;
-        if (program->rename_.size() <= offset)
-            program->rename_.resize(offset + 1);
-        CYIdentifier *&identifier(program->rename_[offset++]);
-        i->second->SetNext(identifier);
-        identifier = i->second;
+        CYIdentifierUsage &rename(context.rename_[offset++]);
+        i->identifier_->SetNext(rename.identifier_);
+        rename.identifier_ = i->identifier_;
+        rename.usage_ += i->identifier_->usage_ + 1;
     }
 
     if (last != NULL) {
@@ -579,6 +636,7 @@ void CYScope::Scope(CYContext &context, CYStatement *&statements) {
 
     for (CYIdentifierValueSet::const_iterator i(identifiers_.begin()); i != identifiers_.end(); ++i)
         if (internal_.find(*i) == internal_.end()) {
+            //std::cout << *i << '=' << offset << std::endl;
             if ((*i)->offset_ < offset)
                 (*i)->offset_ = offset;
             parent_->Merge(context, *i);