1
1
mirror of https://github.com/KenanZhu/AutoLibrary.git synced 2026-06-18 23:43:02 +08:00

refactor(autoscript): 公开 splitTopLevel 并导出常量,消除冗余委托与重复变量

This commit is contained in:
2026-05-18 16:01:10 +08:00
parent 6cf182c8c8
commit c038c8005d
3 changed files with 39 additions and 49 deletions
+11 -4
View File
@@ -33,7 +33,7 @@ from .ASTokenizer import (
) )
__all__ = ["execute", "addTargetVar"] __all__ = ["execute", "addTargetVar", "splitTopLevel"]
# Engine state # Engine state
@@ -69,7 +69,7 @@ _RE_CUR_DATE_OFFSET = re.compile(r"^CURRENT_DATE\s*\+\s*(\d+)$", re.IGNORECASE)
_RE_CUR_TIME_OFFSET = re.compile(r"^CURRENT_TIME\s*\+\s*(\d+)$", re.IGNORECASE) _RE_CUR_TIME_OFFSET = re.compile(r"^CURRENT_TIME\s*\+\s*(\d+)$", re.IGNORECASE)
def _splitTopLevel( def splitTopLevel(
text: str, text: str,
delimiter: str delimiter: str
) -> list: ) -> list:
@@ -281,13 +281,13 @@ def _evaluateCondition(
s = condition_str.strip() s = condition_str.strip()
if not s: if not s:
return False return False
or_parts = _splitTopLevel(s, ".OR.") or_parts = splitTopLevel(s, ".OR.")
if len(or_parts) > 1: if len(or_parts) > 1:
return any( return any(
_evaluateCondition(p.strip(), target_data, line) _evaluateCondition(p.strip(), target_data, line)
for p in or_parts for p in or_parts
) )
and_parts = _splitTopLevel(s, ".AND.") and_parts = splitTopLevel(s, ".AND.")
if len(and_parts) > 1: if len(and_parts) > 1:
return all( return all(
_evaluateCondition(p.strip(), target_data, line) _evaluateCondition(p.strip(), target_data, line)
@@ -466,12 +466,14 @@ class _EngineExecutor(NodeVisitor):
return self._cur_line return self._cur_line
def _incLine( def _incLine(
self self
): ):
self._cur_line += 1 self._cur_line += 1
def visitScript( def visitScript(
self, self,
_node: Script _node: Script
@@ -480,6 +482,7 @@ class _EngineExecutor(NodeVisitor):
for child in _node.body: for child in _node.body:
child.accept(self) child.accept(self)
def visitIf( def visitIf(
self, self,
_node: IfNode _node: IfNode
@@ -506,6 +509,7 @@ class _EngineExecutor(NodeVisitor):
for child in _node.else_body: for child in _node.else_body:
child.accept(self) child.accept(self)
def visitSet( def visitSet(
self, self,
_node: SetNode _node: SetNode
@@ -515,6 +519,7 @@ class _EngineExecutor(NodeVisitor):
full_line = f"SET {_node.target} = {_node.value}" full_line = f"SET {_node.target} = {_node.value}"
_executeSet(full_line, self._target_data, self._line) _executeSet(full_line, self._target_data, self._line)
def visitOp( def visitOp(
self, self,
_node: OpNode _node: OpNode
@@ -525,6 +530,7 @@ class _EngineExecutor(NodeVisitor):
full_line = f"{_node.target} .{op_upper}. {_node.value}" full_line = f"{_node.target} .{op_upper}. {_node.value}"
_executeOperation(full_line, self._target_data, self._line) _executeOperation(full_line, self._target_data, self._line)
def visitPass( def visitPass(
self, self,
_node: PassNode _node: PassNode
@@ -532,6 +538,7 @@ class _EngineExecutor(NodeVisitor):
self._incLine() self._incLine()
def visitUnrecog( def visitUnrecog(
self, self,
_node: UnrecogNode _node: UnrecogNode
+16 -33
View File
@@ -17,7 +17,7 @@ from datetime import (
from .ASObject import ASObject from .ASObject import ASObject
__all__ = ["ASOperator"] __all__ = ["ASOperator", "ARITH_TYPES", "COMPARISON_OPERATORS"]
class ASOperator: class ASOperator:
@@ -96,12 +96,11 @@ class ASOperator:
target_val = target.getValue(target_data) target_val = target.getValue(target_data)
if target_val is None: if target_val is None:
raise ValueError(f"'{target.name}' 的值为空,无法进行运算") raise ValueError(f"'{target.name}' 的值为空,无法进行运算")
if op == ".ADD.": op_name = "ADD" if op == ".ADD." else "SUB" if op == ".SUB." else None
cls._arithAdd(target, target_val, operand, target_data) if op_name is None:
elif op == ".SUB.":
cls._arithSub(target, target_val, operand, target_data)
else:
raise ValueError(f"不支持的操作 '{op}'") raise ValueError(f"不支持的操作 '{op}'")
sign = 1 if op == ".ADD." else -1
cls._arithBinary(target, target_val, operand, target_data, sign, op_name)
@classmethod @classmethod
def _arithBinary( def _arithBinary(
@@ -110,13 +109,13 @@ class ASOperator:
target_val, target_val,
operand: ASObject, operand: ASObject,
target_data: dict, target_data: dict,
sign: int sign: int,
op_name: str = ""
): ):
"""Apply ADD (sign=1) or SUB (sign=-1) per type.""" """Apply arithmetic per type."""
tp = target.var_type tp = target.var_type
raw_op = operand._value raw_op = operand._value
op_name = "ADD" if sign == 1 else "SUB"
if tp == "Date": if tp == "Date":
if not isinstance(target_val, date): if not isinstance(target_val, date):
@@ -129,35 +128,13 @@ class ASOperator:
dt = datetime.combine(datetime.today(), target_val) + delta dt = datetime.combine(datetime.today(), target_val) + delta
new_val = dt.time() new_val = dt.time()
elif tp == "Int": elif tp == "Int":
new_val = int(target_val) + int(raw_op) * sign new_val = int(target_val) + int(raw_op)*sign
elif tp == "Float": elif tp == "Float":
new_val = float(target_val) + float(raw_op) * sign new_val = float(target_val) + float(raw_op)*sign
else: else:
raise ValueError(f"'{tp}' 类型不支持 {op_name} 操作") raise ValueError(f"'{tp}' 类型不支持 {op_name} 操作")
target.setValue(new_val, target_data) target.setValue(new_val, target_data)
@classmethod
def _arithAdd(
cls,
target: ASObject,
target_val,
operand: ASObject,
target_data: dict
):
"""Dispatch ADD per type."""
cls._arithBinary(target, target_val, operand, target_data, 1)
@classmethod
def _arithSub(
cls,
target: ASObject,
target_val,
operand: ASObject,
target_data: dict
):
"""Dispatch SUB per type."""
cls._arithBinary(target, target_val, operand, target_data, -1)
@classmethod @classmethod
def compare( def compare(
cls, cls,
@@ -206,3 +183,9 @@ class ASOperator:
f"无法比较 '{left.name}' ({left.var_type}) " f"无法比较 '{left.name}' ({left.var_type}) "
f"'{right.name}' ({right.var_type})" f"'{right.name}' ({right.var_type})"
) )
# Public constants
# may be used by the GUI orchestration dialog.
ARITH_TYPES = ASOperator._ARITH_TYPES
COMPARISON_OPERATORS = set(ASOperator._COMPARE.keys())
+12 -12
View File
@@ -14,13 +14,16 @@ from autoscript.ASTokenizer import (
from autoscript.ASEngine import ( from autoscript.ASEngine import (
execute, execute,
addTargetVar, addTargetVar,
splitTopLevel,
) )
from autoscript.ASObject import _META_VARS as META_VARS from autoscript.ASObject import _META_VARS as META_VARS
from autoscript.ASObserver import ParsingObserver from autoscript.ASObserver import ParsingObserver
__all__ = [ __all__ = [
"execute", "execute",
"addTargetVar", "addTargetVar",
"splitTopLevel",
"registerDefaultTargetVars", "registerDefaultTargetVars",
"buildMockTargetData", "buildMockTargetData",
"META_VARS", "META_VARS",
@@ -35,18 +38,6 @@ __all__ = [
"ParsingObserver", "ParsingObserver",
] ]
# All variables available to scripts (display_name -> (name, type)).
# This mirrors the old AutoScriptEngine.VARIABLE_META for backward
# compatibility in the UI orchestration dialog.
ALL_VARIABLES: dict = {
"用户名": ("USERNAME", "String"),
"用户启用": ("USER_ENABLE", "Boolean"),
"预约日期": ("RESERVE_DATE", "Date"),
"预约开始时间": ("RESERVE_BEGIN_TIME", "Time"),
"预约结束时间": ("RESERVE_END_TIME", "Time"),
"当前时间": ("CURRENT_TIME", "Time"),
"当前日期": ("CURRENT_DATE", "Date"),
}
# Key paths into target_data dict for each target variable. # Key paths into target_data dict for each target variable.
# (name, type, key_path, display_name) # (name, type, key_path, display_name)
@@ -57,6 +48,15 @@ _TARGET_VAR_DEFS = [
("RESERVE_BEGIN_TIME", "Time", ["reserve_info", "begin_time", "time"], "预约开始时间"), ("RESERVE_BEGIN_TIME", "Time", ["reserve_info", "begin_time", "time"], "预约开始时间"),
("RESERVE_END_TIME", "Time", ["reserve_info", "end_time", "time"], "预约结束时间"), ("RESERVE_END_TIME", "Time", ["reserve_info", "end_time", "time"], "预约结束时间"),
] ]
# All variables (display_name -> (name, type)), derived from target vars + meta vars.
ALL_VARIABLES = {
display_name: (name, var_type)
for name, var_type, _, display_name in _TARGET_VAR_DEFS
} | {
obj.display_name: (obj.name, obj.var_type)
for obj in META_VARS.values()
}
_MOCK_TYPE_VALUES = { _MOCK_TYPE_VALUES = {
"String": "__mock__", "String": "__mock__",
"Boolean": True, "Boolean": True,