import { deepCopy } from './deepCopy.js';
class Grammar {
    constructor(rules, state) {
        this.rules = rules;
        this.defaultState = state;
        this.mainRule = Object.keys(rules)[0];
        this.log = [];
    }
    parse(iterator, mainRule) {
        this.lexer = iterator;
        this.token = this.lexer.next();
        this.state = deepCopy(this.defaultState);
        this.log = [];
        return this.consumeRule(mainRule || this.mainRule);
    }
    matchEndOfFile() {
        return !this.token;
    }
    matchToken(type) {
        return this.token && type === this.token.type;
    }
    consumeToken(type, optional) {
        const token = this.token;
        if (!type || (token && token.type === type)) {
            this.token = this.lexer.next();
            return token;
        }
        else if (optional) {
            return undefined;
        }
        else {
            const got = token ? `"${token.type}"` : 'EOF';
            const error = new SyntaxError(this.lexer.formatError(token, `expected "${type}", got ${got}`));
            error.message += ` (${this.log.join('->')})`;
            throw error;
        }
    }
    consumeRule(rule) {
        this.log.push(rule);
        const result = this.rules[rule].call(this);
        this.log.pop();
        return result;
    }
}
export { Grammar };
