Spaces:
Sleeping
Sleeping
| """ | |
| TCL Parser - Converts TCL expressions into structured representations | |
| The TCL parser handles: | |
| - Symbol recognition and validation | |
| - Causal relationship parsing | |
| - Constraint expression parsing | |
| - Mathematical/logical operation parsing | |
| Grammar encodes causality, not syntax - this is fundamental to TCL design | |
| """ | |
| import re | |
| from typing import List, Dict, Any, Optional, Tuple, Union | |
| from dataclasses import dataclass | |
| from enum import Enum | |
| from .tcl_symbols import SymbolType | |
| class TokenType(Enum): | |
| """Token types for TCL parsing""" | |
| SYMBOL = "symbol" | |
| OPERATOR = "operator" | |
| CAUSALITY = "causality" | |
| CONSTRAINT = "constraint" | |
| NUMBER = "number" | |
| IDENTIFIER = "identifier" | |
| WHITESPACE = "whitespace" | |
| END = "end" | |
| class Token: | |
| """Represents a parsed token""" | |
| type: TokenType | |
| value: str | |
| position: int | |
| line: int | |
| column: int | |
| class TCLParseError(Exception): | |
| """Exception raised during TCL parsing""" | |
| def __init__(self, message: str, position: int, line: int, column: int): | |
| super().__init__(f"Parse error at line {line}, column {column}: {message}") | |
| self.position = position | |
| self.line = line | |
| self.column = column | |
| class ParsedExpression: | |
| """Represents a parsed TCL expression""" | |
| type: str # 'symbol', 'causality', 'constraint', 'operation' | |
| content: Any | |
| position: Tuple[int, int] # (start_line, start_column) | |
| dependencies: List[str] = None # Symbol IDs this expression depends on | |
| def __post_init__(self): | |
| if self.dependencies is None: | |
| self.dependencies = [] | |
| class SymbolReference: | |
| """Represents a reference to a TCL symbol""" | |
| name: str | |
| symbol_type: SymbolType | |
| id: Optional[str] = None | |
| properties: Dict[str, Any] = None | |
| def __post_init__(self): | |
| if self.properties is None: | |
| self.properties = {} | |
| class TCLParser: | |
| """Parser for Thought-Compression Language expressions""" | |
| def __init__(self): | |
| self.current_line = 1 | |
| self.current_column = 1 | |
| self.input = "" | |
| self.position = 0 | |
| # Define symbol patterns | |
| self.symbol_patterns = [ | |
| # Mathematical symbols | |
| (r'[∅∞∑∫∂∀∃¬]', TokenType.SYMBOL), | |
| (r'[ΨΓΛΩΦΔ]', TokenType.SYMBOL), | |
| (r'[→⟹≡≠⊃∪]', TokenType.SYMBOL), | |
| # Complex symbols (combinations) | |
| (r'[ΣΨΓΛ∞Ψ∀Γ]', TokenType.SYMBOL), | |
| # Operators | |
| (r'[+\-*/=<>!]', TokenType.OPERATOR), | |
| # Causality operators | |
| (r'→|⟹|⇒|⤴|⤵', TokenType.CAUSALITY), | |
| # Constraint markers | |
| (r'[{}⟂∥⊥]', TokenType.CONSTRAINT), | |
| # Numbers | |
| (r'\d+\.?\d*', TokenType.NUMBER), | |
| # Identifiers (words) | |
| (r'[a-zA-Z_][a-zA-Z0-9_]*', TokenType.IDENTIFIER), | |
| ] | |
| # Causality patterns | |
| self.causality_patterns = [ | |
| r'(\w+)\s*→\s*(\w+)', # A causes B | |
| r'(\w+)\s*⟹\s*(\w+)', # A implies B | |
| r'(\w+)\s*⇒\s*(\w+)', # A therefore B | |
| ] | |
| # Constraint patterns | |
| self.constraint_patterns = [ | |
| r'\{([^}]+)\}', # {constraint} | |
| r'(\w+)\s*⊥\s*(\w+)', # A perpendicular B | |
| r'(\w+)\s*∥\s*(\w+)', # A parallel B | |
| ] | |
| def parse(self, tcl_input: str) -> List[ParsedExpression]: | |
| """ | |
| Parse TCL input into structured expressions | |
| Args: | |
| tcl_input: TCL expression string to parse | |
| Returns: | |
| List of parsed expressions | |
| Raises: | |
| TCLParseError: If parsing fails | |
| """ | |
| self.input = tcl_input | |
| self.current_line = 1 | |
| self.current_column = 1 | |
| self.position = 0 | |
| expressions = [] | |
| # Parse line by line for better error reporting | |
| lines = tcl_input.split('\n') | |
| for line_num, line in enumerate(lines, 1): | |
| line_expressions = self._parse_line(line, line_num) | |
| expressions.extend(line_expressions) | |
| # Post-process expressions for causality and constraints | |
| processed_expressions = self._post_process_expressions(expressions) | |
| return processed_expressions | |
| def _parse_line(self, line: str, line_number: int) -> List[ParsedExpression]: | |
| """Parse a single line of TCL""" | |
| expressions = [] | |
| # Skip empty lines and comments | |
| line = line.strip() | |
| if not line or line.startswith('//'): | |
| return expressions | |
| # Try to match causality patterns first | |
| for pattern in self.causality_patterns: | |
| matches = list(re.finditer(pattern, line)) | |
| for match in matches: | |
| cause = match.group(1).strip() | |
| effect = match.group(2).strip() | |
| expr = ParsedExpression( | |
| type="causality", | |
| content={ | |
| 'cause': cause, | |
| 'effect': effect, | |
| 'operator': match.group(0) | |
| }, | |
| position=(line_number, match.start() + 1) | |
| ) | |
| expressions.append(expr) | |
| # Remove matched portion to avoid reprocessing | |
| line = line[:match.start()] + line[match.end():] | |
| # Try to match constraint patterns | |
| for pattern in self.constraint_patterns: | |
| matches = list(re.finditer(pattern, line)) | |
| for match in matches: | |
| if len(match.groups()) == 1: | |
| # {constraint} format | |
| constraint = match.group(1).strip() | |
| expr = ParsedExpression( | |
| type="constraint", | |
| content={ | |
| 'constraint': constraint, | |
| 'operator': match.group(0) | |
| }, | |
| position=(line_number, match.start() + 1) | |
| ) | |
| else: | |
| # A ⊥ B or A ∥ B format | |
| expr = ParsedExpression( | |
| type="constraint", | |
| content={ | |
| 'left': match.group(1).strip(), | |
| 'right': match.group(2).strip(), | |
| 'operator': match.group(0) | |
| }, | |
| position=(line_number, match.start() + 1) | |
| ) | |
| expressions.append(expr) | |
| # Remove matched portion | |
| line = line[:match.start()] + line[match.end():] | |
| # Parse remaining symbols and operations | |
| remaining_line = line.strip() | |
| if remaining_line: | |
| symbol_expressions = self._parse_symbols_and_operations(remaining_line, line_number) | |
| expressions.extend(symbol_expressions) | |
| return expressions | |
| def _parse_symbols_and_operations(self, line: str, line_number: int) -> List[ParsedExpression]: | |
| """Parse symbols and operations from remaining line content""" | |
| expressions = [] | |
| # Tokenize the line | |
| tokens = self._tokenize(line) | |
| # Parse based on token patterns | |
| i = 0 | |
| while i < len(tokens): | |
| token = tokens[i] | |
| if token.type == TokenType.SYMBOL: | |
| # Check if this is a complex operation | |
| if i + 2 < len(tokens) and tokens[i + 1].type in [TokenType.OPERATOR, TokenType.CAUSALITY]: | |
| # Operation or causality | |
| operator = tokens[i + 1] | |
| right_operand = tokens[i + 2] if i + 2 < len(tokens) else None | |
| if right_operand: | |
| expr = ParsedExpression( | |
| type="operation", | |
| content={ | |
| 'left': token.value, | |
| 'operator': operator.value, | |
| 'right': right_operand.value | |
| }, | |
| position=(line_number, token.position) | |
| ) | |
| expressions.append(expr) | |
| i += 3 | |
| else: | |
| # Unary operation | |
| expr = ParsedExpression( | |
| type="symbol", | |
| content={'symbol': token.value}, | |
| position=(line_number, token.position) | |
| ) | |
| expressions.append(expr) | |
| i += 1 | |
| else: | |
| # Simple symbol | |
| expr = ParsedExpression( | |
| type="symbol", | |
| content={'symbol': token.value}, | |
| position=(line_number, token.position) | |
| ) | |
| expressions.append(expr) | |
| i += 1 | |
| elif token.type == TokenType.IDENTIFIER: | |
| # Treat identifiers as concept symbols | |
| expr = ParsedExpression( | |
| type="symbol", | |
| content={'symbol': token.value, 'type': 'concept'}, | |
| position=(line_number, token.position) | |
| ) | |
| expressions.append(expr) | |
| i += 1 | |
| elif token.type == TokenType.OPERATOR: | |
| # Skip standalone operators (they should be part of operations) | |
| i += 1 | |
| else: | |
| # Skip other token types | |
| i += 1 | |
| return expressions | |
| def _tokenize(self, text: str) -> List[Token]: | |
| """Tokenize text into TCL tokens""" | |
| tokens = [] | |
| position = 0 | |
| while position < len(text): | |
| matched = False | |
| for pattern, token_type in self.symbol_patterns: | |
| match = re.match(pattern, text[position:]) | |
| if match: | |
| token = Token( | |
| type=token_type, | |
| value=match.group(0), | |
| position=position, | |
| line=self.current_line, | |
| column=self.current_column + position | |
| ) | |
| tokens.append(token) | |
| position += len(match.group(0)) | |
| matched = True | |
| break | |
| if not matched: | |
| # Skip whitespace | |
| if text[position].isspace(): | |
| position += 1 | |
| else: | |
| # Unknown character - treat as identifier continuation | |
| start = position | |
| while position < len(text) and not text[position].isspace(): | |
| position += 1 | |
| token = Token( | |
| type=TokenType.IDENTIFIER, | |
| value=text[start:position], | |
| position=start, | |
| line=self.current_line, | |
| column=self.current_column + start | |
| ) | |
| tokens.append(token) | |
| # Add end token | |
| tokens.append(Token( | |
| type=TokenType.END, | |
| value="", | |
| position=len(text), | |
| line=self.current_line, | |
| column=self.current_column + len(text) | |
| )) | |
| return tokens | |
| def _post_process_expressions(self, expressions: List[ParsedExpression]) -> List[ParsedExpression]: | |
| """Post-process parsed expressions to resolve dependencies and relationships""" | |
| processed = [] | |
| for expr in expressions: | |
| # Add dependencies based on expression type | |
| if expr.type == "causality": | |
| expr.dependencies = [expr.content['cause'], expr.content['effect']] | |
| elif expr.type == "operation": | |
| expr.dependencies = [expr.content['left'], expr.content['right']] | |
| elif expr.type == "symbol": | |
| expr.dependencies = [expr.content['symbol']] | |
| processed.append(expr) | |
| # Sort expressions by dependency order | |
| processed.sort(key=lambda x: len(x.dependencies)) | |
| return processed | |
| def validate_expression(self, expr: ParsedExpression) -> bool: | |
| """Validate a parsed expression for correctness""" | |
| try: | |
| if expr.type == "symbol": | |
| symbol_name = expr.content.get('symbol', '') | |
| return len(symbol_name) > 0 and not any(c.isspace() for c in symbol_name) | |
| elif expr.type == "causality": | |
| cause = expr.content.get('cause', '') | |
| effect = expr.content.get('effect', '') | |
| operator = expr.content.get('operator', '') | |
| return (len(cause) > 0 and len(effect) > 0 and | |
| operator in ['→', '⟹', '⇒']) | |
| elif expr.type == "constraint": | |
| if 'constraint' in expr.content: | |
| constraint = expr.content['constraint'] | |
| return len(constraint) > 0 | |
| else: | |
| left = expr.content.get('left', '') | |
| right = expr.content.get('right', '') | |
| operator = expr.content.get('operator', '') | |
| return (len(left) > 0 and len(right) > 0 and | |
| operator in ['⊥', '∥']) | |
| elif expr.type == "operation": | |
| left = expr.content.get('left', '') | |
| operator = expr.content.get('operator', '') | |
| right = expr.content.get('right', '') | |
| return len(left) > 0 and len(operator) > 0 and len(right) > 0 | |
| return False | |
| except Exception: | |
| return False | |
| def get_expression_info(self, expr: ParsedExpression) -> Dict[str, Any]: | |
| """Get detailed information about a parsed expression""" | |
| return { | |
| 'type': expr.type, | |
| 'content': expr.content, | |
| 'position': expr.position, | |
| 'dependencies': expr.dependencies, | |
| 'valid': self.validate_expression(expr), | |
| 'complexity': len(expr.dependencies) | |
| } | |
| # Example TCL expressions for testing | |
| EXAMPLE_EXPRESSIONS = [ | |
| "Ψ → Γ", # Thought causes concept | |
| "Γ ⊥ Λ", # Concept perpendicular to logic | |
| "∀x (x → ∞Ψ)", # Universal causation to infinite thinking | |
| "ΣΨ = Ψ₁ + Ψ₂ + Ψ₃", # Superthought as sum of thoughts | |
| "ΓΛ ⟹ Δ", # Conceptual logic implies difference | |
| ] | |
| def parse_example_expressions(): | |
| """Parse and display example TCL expressions""" | |
| parser = TCLParser() | |
| print("TCL Parser - Example Expressions") | |
| print("=" * 40) | |
| for i, expr_text in enumerate(EXAMPLE_EXPRESSIONS, 1): | |
| print(f"\nExample {i}: {expr_text}") | |
| print("-" * 30) | |
| try: | |
| parsed = parser.parse(expr_text) | |
| for j, expr in enumerate(parsed): | |
| info = parser.get_expression_info(expr) | |
| print(f" Expression {j + 1}:") | |
| print(f" Type: {info['type']}") | |
| print(f" Content: {info['content']}") | |
| print(f" Dependencies: {info['dependencies']}") | |
| print(f" Valid: {info['valid']}") | |
| print(f" Complexity: {info['complexity']}") | |
| except TCLParseError as e: | |
| print(f" Parse Error: {e}") | |
| if __name__ == "__main__": | |
| parse_example_expressions() |