All Downloads are FREE. Search and download functionalities are using the official Maven repository.

js.ide.codebase.js Maven / Gradle / Ivy

There is a newer version: 0.0.13
Show newest version
var isNodeJs = typeof window === 'undefined' && typeof importScripts === 'undefined';
var prompto = prompto;

if(typeof prompto === 'undefined') {
    prompto = isNodeJs ?
        require("../../../../prompto-javascript/JavaScript-Core/src/test/prompto/parser/PromptoLoader").prompto :
        require('prompto/index');
}

/* a function for inferring dialect from file extension */
function inferDialect(path) {
    return path.substring(path.length-2, path.length-1).toUpperCase();
}

/* a function for parsing prompto code into declarations */
function parse(input, dialect, listener) {
    var klass = prompto.parser[dialect + "CleverParser"];
    var parser = new klass(input);
    parser.removeErrorListeners();
    if(listener)
        parser.addErrorListener(listener);
    return parser.parse();
}

/* a function for producing code from a declaration object */
function unparse(context, decl, dialect) {
    var d = prompto.parser.Dialect[dialect];
    var writer = new prompto.utils.CodeWriter(d, context.newChildContext());
    if(decl.comments) {
        decl.comments.forEach(function (cmt) {
            cmt.toDialect(writer);
        });
    }
    decl.toDialect(writer);
    return writer.toString();
}

/* a function for translating current input to other dialect */
function translate(context, data, from, to) {
    var decls = parse(data, from); // could be cached
    var dialect = prompto.parser.Dialect[to];
    var writer = new prompto.utils.CodeWriter(dialect, context.newChildContext());
    decls.toDialect(writer);
    return writer.toString();
}

/* a utility function to sort by field name */
function sortBy(a, f) {
    return a.sort(function(i1,i2) {
        return (i1[f]>i2[f]) ? 1 : ((i1[f]0;
        });
};

/**
 * An object which represents the delta between 2 catalogs
 * The purpose of this class is to minimize the re-processing in the IDE
 * when code is updated. Typically, various scenarios can occur:
 *  - code body change, this has not impact on the catalog
 *  - declaration removed
 *  - declaration added
 *  - declarations changed, which for global methods adds complexity because
 *  methods are displayed differently depending on their number of prototypes
 *  The below code is not optimized. The optimization is to only redisplay what is needed,
 *  not to optimize the calculation of what needs to be redisplayed.
 *  This follows the assumption that the number of overloads for a method name is generally very low (< 10).
 */
function Delta() {
    this.removed = null;
    this.added = null;
    return this;
}

Delta.prototype.length = function() {
    var length = 0;
    if(this.removed)
        length += this.removed.length();
    if(this.added)
        length += this.added.length();
    return length;
};

Delta.prototype.getContent = function() {
    return { removed : this.removed, added : this.added };
};

Delta.prototype.filterOutDuplicates = function() {
    if(!this.removed && !this.added)
        return 0;
    if(!this.removed)
        return this.added.length();
    if(!this.added)
        return this.removed.length();
    var length = this.filterOutDuplicatesInField("attributes");
    length += this.filterOutDuplicatesInField("methods");
    length += this.filterOutDuplicatesInField("categories");
    length += this.filterOutDuplicatesInField("enumerations");
    length += this.filterOutDuplicatesInField("tests");
    return length;
};

Delta.prototype.filterOutDuplicatesInField = function(field) {
    var fn = field==="methods" ? this.filterOutDuplicatesInMethods : this.filterOutDuplicatesInLists;
    var length = fn.bind(this)(this.removed[field], this.added[field]);
    if(this.removed[field] && !this.removed[field].length)
        delete this.removed[field];
    if(this.added[field] && !this.added[field].length)
        delete this.added[field];
    return length;
};

Delta.prototype.filterOutDuplicatesInLists = function(a, b, field) {
    if(a && b) {
        if(field) {
            sortBy(a, field);
            sortBy(b, field);
        } else {
            a.sort();
            b.sort();
        }
        for(var i=0,j=0;ivb) {
                j++;
            } else {
                i++;
            }
        }
        return a.length + b.length;
    } else if(a)
        return a.length;
    else if(b)
        return b.length;
    else
        return 0;
};

Delta.prototype.filterOutDuplicatesInMethods = function(a, b) {
    if(a && b) {
        sortBy(a, "name");
        sortBy(b, "name");
        for(var i=0,j=0;ib[j].name) {
                j++;
            } else {
                i++;
            }
        }
        return a.length + b.length;
    } else if(a)
        return a.length;
    else if(b)
        return b.length;
    else
        return 0;
};

Delta.prototype.adjustForMovingProtos = function(context) {
    // methods with 1 proto are displayed differently than methods with multiple protos
    // if proto cardinality changes from N to 1 or 1 to N, we need to rebuild the corresponding displays
    if (this.removed && this.removed.methods) {
        this.removed.methods.map(function (method) {
            var decl = context.getRegisteredDeclaration(method.name);
            if (decl && Object.keys(decl.protos).length === 1) // moved from N to 1
                this.adjustMethodForRemovedProtos(method, decl);
        }, this);
    }
    if (this.added && this.added.methods) {
        this.added.methods.map(function (method) {
            var decl = context.getRegisteredDeclaration(method.name);
            if (decl && Object.keys(decl.protos).length - method.protos.length === 1) // moved from 1 to N
                this.adjustMethodForAddedProtos(method, decl);
        }, this);
    }
    // cleanup
    if (this.removed && this.removed.methods) {
        this.removed.methods.map(function (method) {
            if(method.proto_to_remove) {
                method.protos.push(method.proto_to_remove);
                sortBy(method.protos, "proto");
                delete method.proto_to_remove;
            }
        });
    }
    if (this.added && this.added.methods) {
        this.added.methods.map(function (method) {
            if(method.proto_to_add) {
                method.protos.push(method.proto_to_add);
                sortBy(method.protos, "proto");
                delete method.proto_to_add;
            }
        });
    }
};


Delta.prototype.adjustMethodForAddedProtos = function(method, decl)
{
    var proto = this.findPreExistingProto(method, decl);
    if(proto) {
        var main = decl.protos[proto].isEligibleAsMain();
        var proto_to_move = {proto: proto, main: main};
        // add it to the remove list
        if(!this.removed)
            this.removed = new Catalog();
        var removed = this.findOrCreateMethod(this.removed, method.name);
        removed.proto_to_remove = proto_to_move;
        // add it to the add list
        method.proto_to_add = proto_to_move;
    }
};


Delta.prototype.findPreExistingProto = function(method, decl) {
    for(var proto in decl.protos) {
        if(decl.protos.hasOwnProperty(proto)) {
            var found = false;
            for (var i = 0; !found && i < method.protos.length; i++) {
                found = proto === method.protos[i].proto;
            }
            if (!found)
                return proto;
        }
    }
    return null; // TODO throw error?
};

Delta.prototype.adjustMethodForRemovedProtos = function(method, decl) {
    // the below will only loop once
    for (var proto in decl.protos) {
        if (decl.protos.hasOwnProperty(proto)) {
            this.adjustMethodForRemovedProto(method, decl, proto);
        }
    }
};

Delta.prototype.adjustMethodForRemovedProto = function(method, decl, proto) {
    var main = decl.protos[proto].isEligibleAsMain();
    var proto_to_move = { proto: proto, main: main };
    // add it to the remove list
    method.proto_to_remove = proto_to_move;
    // add it to the added list
    if(!this.added)
        this.added = new Catalog();
    var added = this.findOrCreateMethod(this.added, decl.name);
    // avoid adding it twice (it might have just been added)
    added.protos.map(function (current) {
        if (proto_to_move && proto_to_move.proto === current.proto)
            proto_to_move = null; // don't add it
    });
    // not an existing proto ?
    if (proto_to_move)
        added.proto_to_add = proto_to_move;
};

Delta.prototype.findOrCreateMethod = function(catalog, name) {
    if(!catalog.methods)
        catalog.methods = [];
    for(var i=0;i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy