7ac887c776
- Add INSPECT (TALLYING/REPLACING/CONVERTING) with BEFORE/AFTER INITIAL - Add SEARCH/SEARCH ALL with element-assignment path enumeration - Fix _mark_perform compound condition marking via evaluate_tree - Fix EVALUATE TRUE prior_false to collect all MC/DC false sets - Add impossible path filtering (Pass A.5) with trace-to-root conflict detection - Fix multi-line PERFORM VARYING parsing (VARYING/FROM/BY/UNTIL on separate lines) - Remove dead code: agents.py LLM parser (replaced by rule-based _BrParser) - 59 unit tests passing, 5 integration programs verified
164 lines
4.1 KiB
Python
164 lines
4.1 KiB
Python
"""COBOL数据模型 — 所有层共享,无外部依赖"""
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
|
|
# ── 字段定义 ──
|
|
|
|
@dataclass
|
|
class PicInfo:
|
|
type: str = 'unknown' # "numeric" | "alphanumeric" | "alphabetic"
|
|
digits: int = 0
|
|
decimal: int = 0
|
|
length: int = 0
|
|
signed: bool = False
|
|
|
|
|
|
@dataclass
|
|
class FieldDef:
|
|
name: str
|
|
level: int
|
|
pic: str | None = None
|
|
pic_info: PicInfo | None = None
|
|
is_filler: bool = False
|
|
occurs_count: int = 0
|
|
occurs_depending: str | None = None
|
|
redefines: str | None = None
|
|
usage: str | None = None # "COMP" | "COMP-3" | "BINARY" | "PACKED-DECIMAL" | ...
|
|
value: str | None = None
|
|
values: list[str] | None = None
|
|
is_88: bool = False
|
|
parent: str | None = None
|
|
section: str | None = None
|
|
|
|
|
|
# ── 分支树 ──
|
|
|
|
class BrSeq:
|
|
def __init__(self):
|
|
self.children = []
|
|
|
|
def add(self, child):
|
|
self.children.append(child)
|
|
|
|
|
|
class BrIf:
|
|
def __init__(self, condition):
|
|
self.condition = condition
|
|
self.cond_tree = None # 由 core.py 在解析时赋值
|
|
self.true_seq = BrSeq()
|
|
self.false_seq = BrSeq()
|
|
|
|
|
|
class BrEval:
|
|
def __init__(self, subject):
|
|
self.subject = subject
|
|
self.subjects = [] # ALSO 多主体: ['WS-A', 'WS-B'],空=普通模式
|
|
self.when_list = []
|
|
self.other_seq = BrSeq()
|
|
self.has_other = False
|
|
|
|
|
|
class BrPerform:
|
|
def __init__(self, perf_type, condition=None, target=None, thru=None, times=None,
|
|
varying_var=None, varying_from=None, varying_by=None):
|
|
self.perf_type = perf_type
|
|
self.condition = condition
|
|
self.target = target
|
|
self.thru = thru
|
|
self.times = times
|
|
self.varying_var = varying_var
|
|
self.varying_from = varying_from
|
|
self.varying_by = varying_by
|
|
self.body_seq = BrSeq()
|
|
|
|
|
|
class Assign:
|
|
"""赋值节点:MOVE/COMPUTE/ADD/SUBTRACT/MULTIPLY/DIVIDE"""
|
|
def __init__(self, target: str, source_info: dict):
|
|
self.target = target
|
|
self.source_info = source_info
|
|
|
|
|
|
class CallNode:
|
|
"""CALL 子程序调用节点(黑盒模式)"""
|
|
def __init__(self, program_name: str, using_params: list = None):
|
|
self.program_name = program_name
|
|
self.using_params = using_params or []
|
|
# using_params: [{"name": "WS-A", "mechanism": "reference"}, ...]
|
|
# mechanism: "reference" | "content" | "value"
|
|
|
|
|
|
# ── 条件树 ──
|
|
|
|
class CondLeaf:
|
|
def __init__(self, field, op, value):
|
|
self.field = field
|
|
self.op = op
|
|
self.value = value
|
|
|
|
|
|
class CondNot:
|
|
def __init__(self, child):
|
|
self.child = child
|
|
|
|
|
|
class CondAnd:
|
|
def __init__(self, left, right):
|
|
self.left = left
|
|
self.right = right
|
|
|
|
|
|
class CondOr:
|
|
def __init__(self, left, right):
|
|
self.left = left
|
|
self.right = right
|
|
|
|
|
|
class BrSearch:
|
|
"""SEARCH / SEARCH ALL 表查找"""
|
|
def __init__(self, table_name, is_all=False, varying=None):
|
|
self.table_name = table_name
|
|
self.is_all = is_all
|
|
self.varying = varying.upper() if varying else None
|
|
self.at_end_seq = BrSeq()
|
|
self.when_list = [] # [(condition_text, BrSeq)]
|
|
self.cond_trees = [] # [cond_tree, ...]
|
|
self.has_at_end = False
|
|
|
|
|
|
class GoTo:
|
|
"""GO TO 节点:无条件跳转到指定段落"""
|
|
def __init__(self, target: str, body_seq: 'BrSeq' = None):
|
|
self.target = target
|
|
self.body_seq = body_seq or BrSeq()
|
|
|
|
|
|
class ExitNode:
|
|
"""控制流退出节点:EXIT PARAGRAPH / EXIT PERFORM / EXIT SECTION / EXIT PROGRAM"""
|
|
def __init__(self, exit_type: str):
|
|
self.exit_type = exit_type
|
|
|
|
|
|
# ── 约束路径 ──
|
|
|
|
Constraint = tuple # (field, op, value, want_true)
|
|
Path = list[Constraint]
|
|
|
|
|
|
# ── 解析错误 ──
|
|
|
|
@dataclass
|
|
class ParseError:
|
|
line: int
|
|
message: str
|
|
severity: str = 'warning'
|
|
|
|
|
|
@dataclass
|
|
class ProcParseResult:
|
|
tree: BrSeq | None = None
|
|
assignments: dict = field(default_factory=dict)
|
|
errors: list[ParseError] = field(default_factory=list)
|
|
fallback_to_ai: bool = False
|