================
@@ -0,0 +1,315 @@
+"""
+This module implements a couple of utility classes to make writing
+lldb parsed commands more Pythonic.
+The way to use it is to make a class for you command that inherits from 
ParsedCommandBase.
+That will make an LLDBOVParser which you will use for your
+option definition, and to fetch option values for the current invocation
+of your command.  Access to the OV parser is through:
+
+ParsedCommandBase.get_parser()
+
+Next, implement setup_command_definition in your new command class, and call:
+
+  self.get_parser().add_option
+
+to add all your options.  The order doesn't matter for options, lldb will sort 
them
+alphabetically for you when it prints help.
+
+Similarly you can define the arguments with:
+
+  self.get_parser.add_argument
+
+at present, lldb doesn't do as much work as it should verifying arguments, it 
pretty
+much only checks that commands that take no arguments don't get passed 
arguments.
+
+Then implement the execute function for your command as:
+
+    def __call__(self, debugger, args_array, exe_ctx, result):
+
+The arguments will be in a python array as strings.  
+
+You can access the option values using varname you passed in when defining the 
option.  
+If you need to know whether a given option was set by the user or not, you can 
retrieve 
+the option definition array with:
+
+  self.get_options_definition()
+
+look up your element by varname and check the "_value_set" element.
+
+There are example commands in the lldb testsuite at:
+
+llvm-project/lldb/test/API/commands/command/script/add/test_commands.py
+
+FIXME: I should make a convenient wrapper for that. 
+"""
+import inspect
+import lldb
+import sys
+
+class LLDBOVParser:
+    def __init__(self):
+        self.options_array = []
+        self.args_array = []
+
+    # Some methods to translate common value types.  Should return a
+    # tuple of the value and an error value (True => error) if the
+    # type can't be converted.
+    # FIXME: Need a way to push the conversion error string back to lldb.
+    @staticmethod
+    def to_bool(in_value):
+        error = True
+        value = False
+        low_in = in_value.lower()
+        if low_in == "yes" or low_in == "true" or low_in == "1":
+            value = True
+            error = False
+            
+        if not value and low_in == "no" or low_in == "false" or low_in == "0":
+            value = False
+            error = False
+
+        return (value, error)
+
+    @staticmethod
+    def to_int(in_value):
+        #FIXME: Not doing errors yet...
+        return (int(in_value), False)
+
+    def to_unsigned(in_value):
+        # FIXME: find an unsigned converter...
+        # And handle errors.
+        return (int(in_value), False)
+
+    translators = {
+        lldb.eArgTypeBoolean : to_bool,
+        lldb.eArgTypeBreakpointID : to_unsigned,
+        lldb.eArgTypeByteSize : to_unsigned,
+        lldb.eArgTypeCount : to_unsigned,
+        lldb.eArgTypeFrameIndex : to_unsigned,
+        lldb.eArgTypeIndex : to_unsigned,
+        lldb.eArgTypeLineNum : to_unsigned,
+        lldb.eArgTypeNumLines : to_unsigned,
+        lldb.eArgTypeNumberPerLine : to_unsigned,
+        lldb.eArgTypeOffset : to_int,
+        lldb.eArgTypeThreadIndex : to_unsigned,
+        lldb.eArgTypeUnsignedInteger : to_unsigned,
+        lldb.eArgTypeWatchpointID : to_unsigned,
+        lldb.eArgTypeColumnNum : to_unsigned,
+        lldb.eArgTypeRecognizerID : to_unsigned,
+        lldb.eArgTypeTargetID : to_unsigned,
+        lldb.eArgTypeStopHookID : to_unsigned
+    }
+
+    @classmethod
+    def translate_value(cls, value_type, value):
+        error = False
+        try:
+            return cls.translators[value_type](value)
+        except KeyError:
+            # If we don't have a translator, return the string value.
+            return (value, False)
+
+    # FIXME: would this be better done on the C++ side?
+    # The common completers are missing some useful ones.
+    # For instance there really should be a common Type completer
+    # And an "lldb command name" completer.
+    completion_table = {
+        lldb.eArgTypeAddressOrExpression : lldb.eVariablePathCompletion,
+        lldb.eArgTypeArchitecture : lldb.eArchitectureCompletion,
+        lldb.eArgTypeBreakpointID : lldb.eBreakpointCompletion,
+        lldb.eArgTypeBreakpointIDRange : lldb.eBreakpointCompletion,
+        lldb.eArgTypeBreakpointName : lldb.eBreakpointNameCompletion,
+        lldb.eArgTypeClassName : lldb.eSymbolCompletion,
+        lldb.eArgTypeDirectoryName : lldb.eDiskDirectoryCompletion,
+        lldb.eArgTypeExpression : lldb.eVariablePathCompletion,
+        lldb.eArgTypeExpressionPath : lldb.eVariablePathCompletion,
+        lldb.eArgTypeFilename : lldb.eDiskFileCompletion,
+        lldb.eArgTypeFrameIndex : lldb.eFrameIndexCompletion,
+        lldb.eArgTypeFunctionName : lldb.eSymbolCompletion,
+        lldb.eArgTypeFunctionOrSymbol : lldb.eSymbolCompletion,
+        lldb.eArgTypeLanguage : lldb.eTypeLanguageCompletion,
+        lldb.eArgTypePath : lldb.eDiskFileCompletion,
+        lldb.eArgTypePid : lldb.eProcessIDCompletion,
+        lldb.eArgTypeProcessName : lldb.eProcessNameCompletion,
+        lldb.eArgTypeRegisterName : lldb.eRegisterCompletion,
+        lldb.eArgTypeRunArgs : lldb.eDiskFileCompletion,
+        lldb.eArgTypeShlibName : lldb.eModuleCompletion,
+        lldb.eArgTypeSourceFile : lldb.eSourceFileCompletion,
+        lldb.eArgTypeSymbol : lldb.eSymbolCompletion,
+        lldb.eArgTypeThreadIndex : lldb.eThreadIndexCompletion,
+        lldb.eArgTypeVarName : lldb.eVariablePathCompletion,
+        lldb.eArgTypePlatform : lldb.ePlatformPluginCompletion,
+        lldb.eArgTypeWatchpointID : lldb.eWatchpointIDCompletion,
+        lldb.eArgTypeWatchpointIDRange : lldb.eWatchpointIDCompletion,
+        lldb.eArgTypeModuleUUID : lldb.eModuleUUIDCompletion,
+        lldb.eArgTypeStopHookID : lldb.eStopHookIDCompletion
+    }
+
+    @classmethod
+    def determine_completion(cls, arg_type):
+        try:
+            return cls.completion_table[arg_type]
+        except KeyError:
+            return lldb.eNoCompletion
+
+    def get_option_element(self, long_name):
+        # Fixme: Is it worth making a long_option dict holding the rest of
+        # the options dict so this lookup is faster?
+        for item in self.options_array:
+            if item["long_option"] == long_name:
+                return item
+
+        return None
+            
+    def option_parsing_started(self):
+        # This makes the ivars for all the varnames in the array and gives them
+        # their default values.
+        for elem in self.options_array:
+            elem['_value_set'] = False       
----------------
hawkinsw wrote:

Seeing the hardcoded string literals throughout this function makes me think it 
might be good to abstract those behind some constants so that they could be 
changed in the future? 

https://github.com/llvm/llvm-project/pull/70734
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to