UNPKG

tfl-js

Version:

A TypeScript library for parsing and evaluating propositional logic formulas

139 lines 6.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TFLParser = void 0; const formula_1 = require("../types/formula"); const errors_1 = require("../errors"); const lexer_1 = require("./lexer"); class TFLParser { constructor() { this.pos = 0; this.tokens = []; } parse(input) { // console.log('\nParsing input:', input); const lexResult = lexer_1.TFLLexer.tokenize(input); if (lexResult.errors.length > 0) { throw new Error(`Lexing errors: ${lexResult.errors.map(e => e.message).join(", ")}`); } this.tokens = lexResult.tokens; // console.log('Tokens:', JSON.stringify(this.tokens, null, 2)); this.pos = 0; return this.parseFormula(0); } parseFormula(precedence) { // console.log(`\nParseFormula called with precedence ${precedence}`); // console.log('Current token:', this.pos < this.tokens.length ? JSON.stringify(this.tokens[this.pos]) : 'END'); let left = this.parsePrefix(); // console.log('After parsePrefix, left:', JSON.stringify(left, null, 2)); while (this.pos < this.tokens.length) { const token = this.tokens[this.pos]; const nextPrecedence = this.getInfixPrecedence(token); // console.log(`Checking token:`, JSON.stringify(token)); // console.log(`Next precedence: ${nextPrecedence}, Current precedence: ${precedence}`); if (nextPrecedence <= precedence) { // console.log('Breaking due to precedence'); break; } this.pos++; // consume operator left = this.parseInfix(left, token, nextPrecedence); // console.log('After parseInfix, left:', JSON.stringify(left, null, 2)); } // console.log('Returning from parseFormula:', JSON.stringify(left, null, 2)); return left; } parsePrefix() { const token = this.tokens[this.pos]; // console.log('ParsePrefix token:', JSON.stringify(token)); if (token.tokenType === lexer_1.Tokens.AtomicProp) { this.pos++; // console.log('Parsed atomic prop:', token.image); return new formula_1.Atom(token.image); } if (token.tokenType === lexer_1.Tokens.LParen) { // console.log('Found left paren'); this.pos++; const expr = this.parseFormula(0); // console.log('After paren contents:', JSON.stringify(expr, null, 2)); if (this.pos >= this.tokens.length || this.tokens[this.pos].tokenType !== lexer_1.Tokens.RParen) { throw new errors_1.ParseError('Expected closing parenthesis', 0, 0, 0, 'primary'); } this.pos++; // Return the inner expression directly return expr; } if (this.isNegation(token)) { // console.log('Found negation'); this.pos++; const operand = this.parseFormula(TFLParser.PRECEDENCE.NOT); // console.log('Negation operand:', JSON.stringify(operand, null, 2)); return new formula_1.Compound(formula_1.Operator.NOT, operand); } throw new errors_1.ParseError(`Unexpected token: ${token.image}`, 0, 0, 0, 'prefix'); } parseInfix(left, operator, precedence) { // console.log(`\nParseInfix Details:`); // console.log('Operator:', JSON.stringify(operator)); // console.log('Operator Type:', operator.tokenType); // console.log('Left:', JSON.stringify(left, null, 2)); // console.log('Current Precedence:', precedence); const rightPrecedence = precedence - (this.isRightAssociative(operator) ? 1 : 0); // console.log('Right Precedence:', rightPrecedence); const right = this.parseFormula(rightPrecedence); // console.log('Right:', JSON.stringify(right, null, 2)); let result; if (this.isAnd(operator)) result = new formula_1.Compound(formula_1.Operator.AND, left, right); else if (this.isOr(operator)) result = new formula_1.Compound(formula_1.Operator.OR, left, right); else if (this.isIf(operator)) { // console.log('Creating IF compound with:'); // console.log(' Left:', JSON.stringify(left, null, 2)); // console.log(' Right:', JSON.stringify(right, null, 2)); result = new formula_1.Compound(formula_1.Operator.IF, left, right); } else if (this.isIff(operator)) result = new formula_1.Compound(formula_1.Operator.IFF, left, right); else throw new errors_1.ParseError(`Unknown operator: ${operator.image}`, 0, 0, 0, 'infix'); // console.log('Infix result:', JSON.stringify(result, null, 2)); return result; } getInfixPrecedence(token) { const precedence = this.isAnd(token) ? TFLParser.PRECEDENCE.AND : this.isOr(token) ? TFLParser.PRECEDENCE.OR : this.isIf(token) ? TFLParser.PRECEDENCE.IF : this.isIff(token) ? TFLParser.PRECEDENCE.IFF : -1; // console.log(`Precedence for token ${JSON.stringify(token)}: ${precedence}`); return precedence; } isRightAssociative(token) { return this.isIf(token) || this.isIff(token); } isNegation(token) { return [lexer_1.Tokens.StandardNot, lexer_1.Tokens.TflNot, lexer_1.Tokens.EnglishNot].includes(token.tokenType); } isAnd(token) { return [lexer_1.Tokens.StandardAnd, lexer_1.Tokens.TflAnd, lexer_1.Tokens.EnglishAnd].includes(token.tokenType); } isOr(token) { return [lexer_1.Tokens.StandardOr, lexer_1.Tokens.TflOr, lexer_1.Tokens.EnglishOr].includes(token.tokenType); } isIf(token) { return [lexer_1.Tokens.StandardIf, lexer_1.Tokens.TflIf, lexer_1.Tokens.EnglishIf].includes(token.tokenType); } isIff(token) { return [lexer_1.Tokens.StandardIff, lexer_1.Tokens.TflIff, lexer_1.Tokens.EnglishIff].includes(token.tokenType); } } exports.TFLParser = TFLParser; // Precedence levels TFLParser.PRECEDENCE = { ATOM: 0, IF: 1, IFF: 1, OR: 2, AND: 3, NOT: 4 }; //# sourceMappingURL=parser.js.map