import { FuzzyFormula, FuzzyOperator, FuzzyHedge } from '../types.js';
export class FuzzyParser {
/**
* Parse fuzzy logic expressions
* Supports:
* - Fuzzy propositions with degrees: hot(0.8)
* - Hedges: very hot, somewhat cold
* - Fuzzy operators: AND, OR, NOT, IMPLIES
* - Membership degrees: temperature IS hot
*/
parse(input: string): FuzzyFormula {
// Normalize input
input = input.trim()
.replace(/\s+/g, ' ')
.replace(/and/gi, 'AND')
.replace(/or/gi, 'OR')
.replace(/not/gi, 'NOT')
.replace(/implies/gi, 'IMPLIES')
.replace(/→/g, 'IMPLIES')
.replace(/∧/g, 'AND')
.replace(/∨/g, 'OR')
.replace(/¬/g, 'NOT');
return this.parseExpression(input);
}
private parseExpression(input: string): FuzzyFormula {
// Check for implications
const impliesMatch = input.match(/^(.+?)\s+IMPLIES\s+(.+)$/i);
if (impliesMatch) {
return {
type: 'compound',
operator: 'IMPLIES' as FuzzyOperator,
operands: [
this.parseExpression(impliesMatch[1].trim()),
this.parseExpression(impliesMatch[2].trim())
]
};
}
// Check for OR
const orMatch = input.match(/^(.+?)\s+OR\s+(.+)$/i);
if (orMatch) {
return {
type: 'compound',
operator: 'OR' as FuzzyOperator,
operands: [
this.parseExpression(orMatch[1].trim()),
this.parseExpression(orMatch[2].trim())
]
};
}
// Check for AND
const andMatch = input.match(/^(.+?)\s+AND\s+(.+)$/i);
if (andMatch) {
return {
type: 'compound',
operator: 'AND' as FuzzyOperator,
operands: [
this.parseExpression(andMatch[1].trim()),
this.parseExpression(andMatch[2].trim())
]
};
}
// Check for NOT
if (input.startsWith('NOT ')) {
return {
type: 'compound',
operator: 'NOT' as FuzzyOperator,
operands: [this.parseExpression(input.substring(4).trim())]
};
}
// Check for hedged expressions
const hedgeMatch = input.match(/^(very|somewhat|slightly|extremely)\s+(.+)$/i);
if (hedgeMatch) {
return {
type: 'hedged',
hedge: hedgeMatch[1].toLowerCase() as FuzzyHedge,
operands: [this.parseExpression(hedgeMatch[2].trim())]
};
}
// Check for fuzzy atom with degree
const degreeMatch = input.match(/^(\w+)\(([\d.]+)\)$/);
if (degreeMatch) {
return {
type: 'atom',
atom: degreeMatch[1],
degree: parseFloat(degreeMatch[2])
};
}
// Check for membership expression
const membershipMatch = input.match(/^(\w+)\s+IS\s+(\w+)$/i);
if (membershipMatch) {
return {
type: 'atom',
atom: `${membershipMatch[1]}_IS_${membershipMatch[2]}`
};
}
// Simple atom
return {
type: 'atom',
atom: input
};
}
}