from tree_sitter import Parser # tree-sitter-c-sharp pip package provides the C# language. from tree_sitter_languages import get_language # helper wrapper (optional) import re def parse_csharp(code: str) -> dict: """ Parses a C# script and returns a simple AST-like dict: { "classes": [ { "name": "Foo", "methods": [ {"name": "Update", "body": "..."} ] } ] } """ result = {"classes": []} try: # try tree-sitter approach from tree_sitter import Parser from tree_sitter_c_sharp import CSHARP_LANGUAGE parser = Parser() parser.set_language(CSHARP_LANGUAGE) tree = parser.parse(bytes(code, "utf8")) root = tree.root_node def traverse(node): classes = [] for child in node.children: if child.type == "class_declaration": class_name = None methods = [] # get class name for grand in child.children: if grand.type == "identifier": class_name = code[grand.start_byte:grand.end_byte] if grand.type == "method_declaration": method_name = None body = "" for g in grand.children: if g.type == "identifier": method_name = code[g.start_byte:g.end_byte] if g.type == "block": body = code[g.start_byte:g.end_byte] methods.append({"name": method_name, "body": body}) classes.append({"name": class_name, "methods": methods}) # recurse into namespaces or other nodes classes.extend(traverse(child)) return classes result["classes"] = traverse(root) return result except Exception: # Fallback using regex classes = [] class_matches = re.finditer(r'class\s+(\w+)\s*:\s*MonoBehaviour\s*{', code) for m in class_matches: cls = m.group(1) methods = [] for mm in re.finditer(r'(void|public)\s+(Start|Update|FixedUpdate)\s*\([^\)]*\)\s*{', code): method_name = mm.group(2) start = mm.end() depth = 1 i = start while i < len(code) and depth > 0: if code[i] == '{': depth += 1 elif code[i] == '}': depth -= 1 i += 1 body = code[start:i-1].strip() methods.append({"name": method_name, "body": body}) classes.append({"name": cls, "methods": methods}) result["classes"] = classes return result