"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Pairing = exports.PairingAnalyzer = void 0;
const errors_1 = require("@ot-builder/errors");
const operator_1 = require("../../../../interp/operator");
const mir_1 = require("../../mir");
const rule_set_1 = require("../subr/rule-set");
const ir_key_provider_1 = require("./ir-key-provider");
const pairing_1 = require("./pairing");
function buildInput(limits, session, source) {
    const input = new pairing_1.Input(mir_1.Mir.nop());
    let h = 0;
    for (const ir of source) {
        if (h >= limits.maxStack) {
            // We are too tall, add a barrier
            session.append(input, mir_1.Mir.nop());
        }
        // Skip END-CHAR -- we will add it back later
        if (!(ir.type === mir_1.MirType.Operator && ir.opCode === operator_1.CharStringOperator.EndChar)) {
            session.append(input, ir);
        }
        h += ir.stackRise;
    }
    return input;
}
class PairingAnalyzer {
    constructor() {
        this.pairSession = new pairing_1.Session(ir_key_provider_1.MirKeyProvider);
        this.inputs = [];
        // NonTerminalBuilder<Mir>
        this.nNonTerminal = 0;
    }
    addInput(limits, seq) {
        this.inputs.push(buildInput(limits, this.pairSession, seq));
    }
    createNonTerminal(a, b) {
        return {
            type: mir_1.MirType.NonTerminal,
            id: this.nNonTerminal++,
            stackRise: a.stackRise + b.stackRise,
            stackRidge: Math.max(1, a.stackRidge, a.stackRise + b.stackRidge)
        };
    }
    // RuleBuilder<Mir, Rule, Rule>
    createNonTerminalRule(symbol, parts) {
        if (symbol.type !== mir_1.MirType.NonTerminal)
            throw errors_1.Errors.Unreachable();
        return new rule_set_1.NTRuleStub(symbol, parts);
    }
    createInputRule(parts) {
        return new rule_set_1.Rule(parts);
    }
    analyze(into) {
        for (const rule of this.pairSession.doCompress(this, this)) {
            into.nonTerminalRules[rule.symbol.id] = new rule_set_1.Rule(rule.parts);
        }
        for (const input of this.inputs) {
            into.inputRules.push(this.pairSession.inputToRule(input, this));
        }
    }
}
exports.PairingAnalyzer = PairingAnalyzer;
exports.Pairing = {
    create: () => new PairingAnalyzer()
};
//# sourceMappingURL=analyzer.js.map