================ @@ -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) ---------------- bulbazord wrote:
I think I missed that the first time I read this. Thanks for clarifying. I wonder if it might be worth introducing a `NamedTuple` type representing this if it's going to be the interface we go with? 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