From aed8deea819aa8113dcefedcd82ffbe14c2e048a Mon Sep 17 00:00:00 2001 From: Emily Boudreaux Date: Wed, 26 Feb 2025 12:30:50 -0500 Subject: [PATCH] fix(utils/defaultConfig): defaultConfig generator ignores comments now --- utils/defaultConfig/defaults.yaml | 26 +++++-- utils/defaultConfig/generateDefaultConfig.py | 77 ++++++++++++++++---- utils/defaultConfig/readme.md | 2 +- 3 files changed, 86 insertions(+), 19 deletions(-) diff --git a/utils/defaultConfig/defaults.yaml b/utils/defaultConfig/defaults.yaml index 6065fee..e9c974d 100644 --- a/utils/defaultConfig/defaults.yaml +++ b/utils/defaultConfig/defaults.yaml @@ -1,11 +1,27 @@ -opac: - lowTemp: - numeric: - maxIter: 10 +Poly: + Solver: + ViewInitialGuess: false Probe: GLVis: Visualization: true Host: localhost - Port: '19916' + Port: 19916 LogManager: DefaultLogName: 4DSSE.log + +# This file was auto-generated by generateDefaultConfig.py +# Do not modify this file directly. + +#=================================== TYPE HINTS =================================== + +# Poly: +# Solver: +# ViewInitialGuess: bool +# Probe: +# GLVis: +# Visualization: bool +# Host: std::string +# Port: int +# LogManager: +# DefaultLogName: std::string +# diff --git a/utils/defaultConfig/generateDefaultConfig.py b/utils/defaultConfig/generateDefaultConfig.py index 9f7bb33..226a3ab 100644 --- a/utils/defaultConfig/generateDefaultConfig.py +++ b/utils/defaultConfig/generateDefaultConfig.py @@ -1,6 +1,24 @@ import os import re import yaml +from io import StringIO + +from tree_sitter import Language, Parser +import tree_sitter_cpp as tscpp + +CPP_LANGUAGE = Language(tscpp.language()) + +def remove_comments_cpp(source_code): + parser = Parser(CPP_LANGUAGE) + tree = parser.parse(source_code.encode()) + def extract_code(node): + if node.type in ['comment']: + return '' + elif node.children: + return ''.join(extract_code(child) for child in node.children) + return source_code[node.start_byte:node.end_byte] + extractedCode = extract_code(tree.root_node) + return extractedCode # Regular expression to match .get("a:b:c", x) pattern = re.compile(r'\.get<([^>]+)>\("([^"]+)",\s*([^);]+)\)') @@ -11,17 +29,17 @@ def parse_value(value, type_hint): # Handle common types if type_hint in {"int", "long"}: - return int(value) + return (int(value), type_hint) elif type_hint in {"float", "double"}: - return float(value) + return (float(value), type_hint) elif type_hint == "bool": - return value.lower() in {"true", "1"} + return (value.lower() in {"true", "1"}, type_hint) elif value.startswith('"') and value.endswith('"'): - return value.strip('"') # Remove quotes for string literals + return (value.strip('"'), type_hint) # Remove quotes for string literals elif value.startswith("'") and value.endswith("'"): - return value.strip("'") # Remove single quotes + return (value.strip("'"), type_hint) # Remove single quotes - return value # Return as-is if unsure + return (value, type_hint) # Return as-is if unsure def insert_into_dict(hierarchy_dict, keys, value, type_hint): """Recursively inserts values into a nested dictionary.""" @@ -42,19 +60,51 @@ def scan_files(directory): if file.endswith(('.cpp', '.h', '.c', '.hpp')): file_path = os.path.join(root, file) with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: - for line in f: - match = pattern.search(line) - if match: - type_hint, hierarchy, value = match.groups() - keys = hierarchy.split(":") - insert_into_dict(hierarchy_dict, keys, value, type_hint) + noCommentSourceCode = remove_comments_cpp(f.read()) + matchs = pattern.finditer(noCommentSourceCode) + for match in matchs: + print(f"Match: {match.group()}") + type_hint, hierarchy, value = match.groups() + keys = hierarchy.split(":") + insert_into_dict(hierarchy_dict, keys, value, type_hint) return hierarchy_dict +def split_dict_recursive(originalDict): + dataDict = {} + typeDict = {} + + for key, value in originalDict.items(): + if isinstance(value, dict): # If the value is another dictionary, recurse + dataDict[key], typeDict[key] = split_dict_recursive(value) + elif isinstance(value, tuple) and len(value) == 2: # If it's a tuple, split it + dataDict[key] = value[0] # First element is data + typeDict[key] = value[1] # Second element is type hint + else: + raise ValueError(f"Unexpected structure in dictionary at key '{key}': {value}") + + return dataDict, typeDict + def save_yaml(data, output_file): """Saves the nested dictionary to a YAML file.""" + options, types = split_dict_recursive(data) with open(output_file, 'w', encoding='utf-8') as f: - yaml.dump(data, f, default_flow_style=False, sort_keys=False, indent=4) + yaml.dump(options, f, default_flow_style=False, sort_keys=False, indent=4) + with open(output_file, 'a') as f: + f.write("\n") + f.write("# This file was auto-generated by generateDefaultConfig.py\n") + f.write("# Do not modify this file directly.\n") + f.write('\n#') + f.write('='*35 + " TYPE HINTS " + '='*35 + '\n') + f.write('\n') + + type_file = StringIO() + yaml.dump(types, type_file, default_flow_style=False, sort_keys=False, indent=4) + # write types yaml out put with # in front of each line + with open(output_file, 'a') as f: + for line in type_file.getvalue().split('\n'): + f.write(f"# {line}\n") + if __name__ == "__main__": import argparse @@ -64,6 +114,7 @@ if __name__ == "__main__": args = parser.parse_args() extracted_data = scan_files(args.directory) + print(extracted_data) save_yaml(extracted_data, args.output) print(f"✅ YAML file generated: {args.output}") diff --git a/utils/defaultConfig/readme.md b/utils/defaultConfig/readme.md index c25b38a..75a4b83 100644 --- a/utils/defaultConfig/readme.md +++ b/utils/defaultConfig/readme.md @@ -2,7 +2,7 @@ Small tool to quickly generate a YAML config file which encodes all the default options used in 4DSSE. All c, c++, h, and hpp in the src directory are scanned and the config variables and their default values pulled out. ## Usage -- You must have python installed +- You must have python installed along with tree-sitter and tree-sitter-cpp (for source code parsing) ```bash ./generateDefaultConfig.sh