#!/usr/bin/env python3 """Convert C# 7/8 features in ONIAgentBridge.cs to C# 6 compatible code. DEPRECATED: The mod source (ONIAgentBridge.cs) has been rewritten to use if-else chains. This script is kept for historical reference only and should not be run on the current source. """ import re with open('mod/ONIAgentBridge.cs', 'r') as f: content = f.read() # 1. Convert tuple switch at ProcessRequest to if-else chain # Find the switch and replace it old_switch_start = """ switch (path, method) {""" # Read the entire switch block and reconstruct lines = content.split('\n') new_lines = [] i = 0 while i < len(lines): line = lines[i] # Find the C# 7 tuple switch if 'switch (path, method)' in line and '{' in lines[i+1]: new_lines.append(' // --- C# 6 compatible dispatch ---') new_lines.append(' bool _handled = false;') i += 2 # skip "switch (path, method)" and "{" while i < len(lines): stripped = lines[i].strip() # Check for case pattern: case ("...", "..."): m = re.match(r'case \("([^"]+)", "([^"]+)"\):', stripped) if m: endpoint = m.group(1) method = m.group(2) indent = lines[i][:len(lines[i]) - len(lines[i].lstrip())] new_lines.append(f'{indent}else if (path == "{endpoint}" && method == "{method}")') new_lines.append(f'{indent}{{') new_lines.append(f'{indent} _handled = true;') i += 1 # Copy lines until "break;" while i < len(lines) and lines[i].strip() != 'break;': new_lines.append(lines[i]) i += 1 new_lines.append(f'{indent}}}') i += 1 # skip "break;" continue # Check for default case if stripped == 'default:': i += 1 # Skip the opening brace if lines[i].strip() == '{': i += 1 new_lines.append(' if (!_handled)') new_lines.append(' {') while i < len(lines): if lines[i].strip() == '}' and not _is_end_of_method(lines, i): # This could be the switch closing brace # Check if next line is the method closing break new_lines.append(lines[i]) i += 1 new_lines.append(' }') # Skip the closing brace of the switch if lines[i].strip() == '}': i += 1 continue # Check for closing brace of switch if stripped == '}': i += 1 break # Any other content inside switch (shouldn't happen) new_lines.append(lines[i]) i += 1 continue new_lines.append(line) i += 1 content = '\n'.join(new_lines) def _is_end_of_method(lines, idx): """Check if this } ends a method (next non-blank is a method or class member).""" for j in range(idx+1, min(idx+10, len(lines))): s = lines[j].strip() if s == '' or s.startswith('//') or s.startswith('/*'): continue if s.startswith('private ') or s.startswith('public ') or s.startswith('internal ') or s.startswith('static ') or s.startswith('}'): return True return False return False # 2. Fix switch expressions (C# 8): `wireType switch { ... }` -> if-else # Pattern: string buildingId = wireType switch { "heavy" => "HeaviWatWire", ... } def fix_switch_expr(match): full = match.group(0) var_name = match.group(1) # Parse the switch arms # Extract the expression after "= " body = match.group(2) return full # placeholder, we'll handle below # Fix: string buildingId = wireType switch { "heavy" => "HeaviWatWire", _ => "Wire" }; # Convert to: string buildingId; if (wireType == "heavy") buildingId = "HeaviWatWire"; else ... for pattern in [ (r'wireType switch\s*\{([^}]+)\}', 'wireType'), (r'error switch\s*\{([^}]+)\}', 'error'), (r'i switch\s*\{([^}]+)\}', 'i'), ]: pat, varname = pattern matches = list(re.finditer(pat, content)) for m in reversed(matches): body = m.group(1) arms = re.findall(r'"([^"]*)"\s*=>\s*"([^"]*)"', body) default = re.findall(r'_\s*=>\s*(null|"[^"]*")', body) if varname == 'i': # label assignment replacements = [] for key, val in arms: replacements.append(f' if ({varname} == {key}) label = "{val}";') if default: replacements.append(f' else label = {default[0]};') new_code = '\n'.join(replacements) else: # Find the variable being assigned start = m.start() # Look backwards to find the variable name line_start = content.rfind('\n', 0, start) + 1 line_before = content[line_start:start] var_match = re.match(r'\s*(?:\w+\s+)?(\w+)\s*=\s*$', line_before) indent = ' ' * 16 if varname == 'wireType': # Multiple instances in wire building, find each by context context_before = content[max(0,start-200):start] if 'bridgeId' in context_before: varname_full = 'bridgeId' else: varname_full = 'buildingId' else: varname_full = varname lines_code = [f' string {varname_full};'] first = True for key, val in arms: prefix = 'if' if first else 'else if' lines_code.append(f' {prefix} ({varname} == "{key}") {varname_full} = "{val}";') first = False if default: dval = default[0] lines_code.append(f' else {varname_full} = {dval};') new_code = '\n'.join(lines_code) # Replace the assignment line + switch expression # Find the full assignment assign_start = content.rfind('\n', 0, start) assign_end = m.end() while assign_end < len(content) and content[assign_end] != '\n': assign_end += 1 old = content[assign_start:assign_end] content = content[:assign_start] + '\n' + new_code + content[assign_end:] # Write result with open('mod/ONIAgentBridge.cs', 'w') as f: f.write(content) print('Done. Checking for remaining C# 7+ features...') # Verify remaining = re.findall(r'\bswitch\b', content) print(f'Remaining "switch" keywords: {len(remaining)}') # Count them for i, line in enumerate(content.split('\n')): if 'switch' in line and not line.strip().startswith('//') and 'ProcessRequest' not in line: sline = line.strip() if 'if (' not in line and 'dictionary' not in line.lower() and 'dispatch' not in line: print(f' Line ~{i}: {sline[:80]}')