<commit_before>yate.AST.jpath = {};

yate.AST.jpath.options = {
    base: 'inline_expr'
};

yate.AST.jpath._type = yate.types.NODESET;

yate.AST.jpath.isLocal = yate.true;

yate.AST.jpath.action = function() {
    var key = this.yate(); // Каноническая запись jpath.

    var state = this.state;
    var scope = this.getScope(); // scope, в котором этот jpath имеет смысл.
                                 // Например, .foo.bar[ .count > a + b ] имеет смысл только внутри scope'а,
                                 // в котором определены переменные a и b.

    // Если этот jpath еще не хранится в scope, то добаляем его туда.
    var jid = scope.jkeys[key];
    if (jid === undefined) {
        jid = scope.jkeys[key] = state.jid++;
        scope.jpaths.push(this);
    }

    this.Jid = jid; // Запоминаем id-шник.
    this.Key = key;
};

yate.AST.jpath.validate = function() {
    var context = this.Context;
    if (context && !context.type( yate.types.NODESET )) {
        context.error('Invalid type. Should be NODESET');
    }
};

// oncast = function() {},

// Возвращаем значение последнего nametest'а или же ''.
// Например, lastName(/foo/bar[id]) == 'bar', lastName(/) == ''.
yate.AST.jpath.lastName = function() { // FIXME: Унести это в jpath_steps?
    var steps = this.Steps;
    if (!steps) { return ''; }
    var l = steps.Items.length;
    return (l) ? steps.Items[l - 1].Name : '';
};

yate.AST.jpath.getScope = function() {
    return this.Steps.getScope();
};
<commit_msg>Правильно вычисляем lastName в jpath с предикатами и т.д.<commit_after>yate.AST.jpath = {};

yate.AST.jpath.options = {
    base: 'inline_expr'
};

yate.AST.jpath._type = yate.types.NODESET;

yate.AST.jpath.isLocal = yate.true;

yate.AST.jpath.action = function() {
    var key = this.yate(); // Каноническая запись jpath.

    var state = this.state;
    var scope = this.getScope(); // scope, в котором этот jpath имеет смысл.
                                 // Например, .foo.bar[ .count > a + b ] имеет смысл только внутри scope'а,
                                 // в котором определены переменные a и b.

    // Если этот jpath еще не хранится в scope, то добаляем его туда.
    var jid = scope.jkeys[key];
    if (jid === undefined) {
        jid = scope.jkeys[key] = state.jid++;
        scope.jpaths.push(this);
    }

    this.Jid = jid; // Запоминаем id-шник.
    this.Key = key;
};

yate.AST.jpath.validate = function() {
    var context = this.Context;
    if (context && !context.type( yate.types.NODESET )) {
        context.error('Invalid type. Should be NODESET');
    }
};

// oncast = function() {},

// Возвращаем значение последнего nametest'а или же ''.
// Например, lastName(/foo/bar[id]) == 'bar', lastName(/) == ''.
yate.AST.jpath.lastName = function() { // FIXME: Унести это в jpath_steps?
    var steps = this.Steps.Items;
    for (var i = steps.length; i--; ) {
        var step = steps[i];
        if (step.is('jpath_nametest')) {
            return step.Name;
        }
    }
    return '';
};

yate.AST.jpath.getScope = function() {
    return this.Steps.getScope();
};

{'fraction_non_alphanumeric': 0.1554119547657512, 'fraction_numerical': 0.00032310177705977385, 'mean_word_length': 2.297124600638978, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3778545', 'n_tokens_mistral': 1138, 'n_tokens_neox': 1189, 'n_words': 259}