def parse_input(input_str):
"""
解析输入字符串,提取变量名、方法路径、参数和右侧值。
"""
tree = ast.parse(input_str)
# 将 AST 转换为字符串
output_name = None
method_path = None
converted_args = []
right_value = None
for node in ast.walk(tree):
# 检查是否是赋值语句
if isinstance(node, ast.Assign):
# 提取目标变量名或属性路径
if isinstance(node.targets[0], ast.Name): # 普通变量名
output_name = node.targets[0].id
elif isinstance(node.targets[0], ast.Attribute): # 属性赋值
output_name = extract_attribute_path(node.targets[0])
else:
raise TypeError(f"Unsupported target type: {type(node.targets[0])}")
# 提取右侧值
right_value = extract_right_value(node.value)
# 如果右侧是函数调用,提取方法路径和参数
if isinstance(node.value, ast.Call):
method_path, converted_args = extract_method_and_args(node.value)
# 检查是否是直接的函数调用
elif isinstance(node, ast.Call):
method_path, converted_args = extract_method_and_args(node)
return output_name, method_path, converted_args, right_value
def extract_method_and_args(call_node):
"""
从函数调用节点中提取方法路径和参数。
"""
# 提取方法路径
if isinstance(call_node.func, ast.Attribute): # 方法调用
method_path = extract_attribute_path(call_node.func)
elif isinstance(call_node.func, ast.Name): # 普通函数调用
method_path = call_node.func.id
else:
raise TypeError(f"Unsupported function type: {type(call_node.func)}")
# 提取参数值
converted_args = []
for arg in call_node.args:
if isinstance(arg, ast.Str): # 字符串字面量
converted_args.append(arg.s)
elif isinstance(arg, ast.Num): # 数字字面量
converted_args.append(arg.n)
elif isinstance(arg, ast.UnaryOp): # 一元操作符(如负号)
if isinstance(arg.op, ast.USub): # 负号
operand = arg.operand
if isinstance(operand, ast.Num):
converted_args.append(-operand.n)
else:
raise TypeError(f"Unsupported UnaryOp operand: {type(operand)}")
else:
raise TypeError(f"Unsupported UnaryOp operator: {type(arg.op)}")
elif isinstance(arg, ast.Name): # 变量名
converted_args.append(arg.id)
else:
raise TypeError(f"Unsupported argument type: {type(arg)}")
return method_path, converted_args
def extract_attribute_path(attribute_node):
"""
递归提取嵌套属性路径。
"""
parts = []
current_node = attribute_node
while isinstance(current_node, ast.Attribute):
parts.append(current_node.attr)
current_node = current_node.value
if isinstance(current_node, ast.Name):
parts.append(current_node.id)
else:
raise TypeError(f"Unsupported node type in attribute path: {type(current_node)}")
return ".".join(reversed(parts))
def extract_right_value(value_node):
"""
提取右侧值。
"""
if isinstance(value_node, ast.Call):
return None # 如果右侧是函数调用,则返回 None
elif isinstance(value_node, ast.Str):
return value_node.s
elif isinstance(value_node, ast.Num):
return value_node.n
elif isinstance(value_node, ast.UnaryOp): # 处理一元操作符
if isinstance(value_node.op, ast.USub): # 负号
operand = value_node.operand
if isinstance(operand, ast.Num):
return -operand.n
else:
raise TypeError(f"Unsupported UnaryOp operand: {type(operand)}")
else:
raise TypeError(f"Unsupported UnaryOp operator: {type(value_node.op)}")
else:
raise TypeError(f"Unsupported value type: {type(value_node)}")
# 测试用例 1:属性赋值 + 数字字面量
input_str = "obj.attr = 10"
print(parse_input(input_str))
# 输出: ('obj.attr', None, [], 10)
# 测试用例 2:属性赋值 + 字符串字面量
input_str = "obj.attr = 'hello'"
print(parse_input(input_str))
# 输出: ('obj.attr', None, [], 'hello')
# 测试用例 3:属性赋值 + 变量
input_str = "obj.attr = var"
print(parse_input(input_str))
# 输出: ('obj.attr', None, [], 'var')
# 测试用例 4:属性赋值 + 函数调用
input_str = "obj.attr = func('param1')"
print(parse_input(input_str))
# 输出: ('obj.attr', 'func', ['param1'], 'FunctionCall')
# 测试用例 5:属性赋值 + 表达式
input_str = "obj.attr = 10 + 5"
print(parse_input(input_str))
# 输出: ('obj.attr', None, [], 'Expression')
树结构FreeCADGui.Selection.addSelection('Cube_Document','Body','BaseShape.Edge7',9.4199,-9,1):
Module(
body=[
Expr(
value=Call(
func=Attribute(
value=Attribute(
value=Name(id='FreeCADGui', ctx=Load()),
attr='Selection',
ctx=Load()),
attr='addSelection',
ctx=Load()),
args=[
Constant(value='Cube_Document'),
Constant(value='Body'),
Constant(value='BaseShape.Edge7'),
Constant(value=9.4199),
UnaryOp(
op=USub(),
operand=Constant(value=9)),
Constant(value=1)],
keywords=[]))],
type_ignores=[])
if __name__ == "__main__":
command = "FreeCADGui.Selection.addSelection('Cube_Document','Body','BaseShape.Edge7',9.4199,-9,1)"
output_name, method_path, converted_args, right_value = parse_input(command)
tree = ast.parse(command)
# 将 AST 转换为字符串
ast_str = ast.dump(tree, indent=4)
# 保存到本地文件
with open("ast_output.txt", "w", encoding="utf-8") as f:
f.write(ast_str)
print(f"Output Name: {output_name}")
print(f"Method Path: {method_path}")
print(f"Converted Args: {converted_args}")
print(f"Right Value: {right_value}")