Pyparsing:将检查分成 2 个单独的部分时出现问题,如果第一部分的检查失败,它应该继续检查第二部分

Pyparsing: Problem splitting up a check in 2 seperate parts, where it should continue the check with the 2nd part if the check on the first part fails

我们为我们的客户定义了一种domain-specific(自动)测试(脚本)语言来简化测试用例的设置。

ASC-file 中的每个测试都由三部分组成:

test <name> - <options> # <-- defines the start of a test and some general options
    <testheader>        # <-- contains a number of header commands which need to be always filled in
    <testbody>          # <-- the real test-actions

<testheader><testbody> 中都允许使用白线(以提高测试用例的可读性)

为了检查这些 ASC-file 中的定义是否正确,我们制作了一个 validator-script,它按以下方式检查测试:

# definitions of valid_header_command and valid_test_command not listed here since they themselves are not of importance for the question (just lists with definitions of keywords for those particular sections)
anyotherline = restOfLine - Optional(LineEnd())

test_command = NotAny(OneOfKeywords('if', 'elif', 'else', 'fi') | eot) - (valid_header_command | valid_test_command | anyotherline)

block = Forward()
pre_post_block = Forward()

if_statement = Keyword('if') - vp_expression - eol
then_block = ZeroOrMore(block)
elif_block = Keyword('elif') - vp_expression - eol - ZeroOrMore(block)
else_block = Keyword('else') - eol - ZeroOrMore(block)
fi_statement = Keyword('fi') - eol

conditional_block = if_statement - then_block - ZeroOrMore(elif_block) - Optional(else_block) - fi_statement
block << ( OneOrMore(test_command) | conditional_block ) # pylint: disable=expression-not-assigned

test_implementation = (OneOrMore(block) + eot).setParseAction(self._parseaction_validate_mandatory_header_commands)

test_name = CharsNotIn(' +:!,?;@=()\n\r')
test_options = ( #option-definitios
               )
test_definition = Keyword('test') - White(' ') - test_name.addParseAction(self._parseaction_validate_unique_testcase).addParseAction(self._parseaction_reset_per_testcase_data) - test_options - eol
# if we can't find a test_definition, but we can find a line with something on it (so not the end of file), then report an error
testcase = (test_definition - test_implementation) | (restOfLine + ~StringEnd() + LineEnd()).setParseAction(self._parseaction_errorExpectingNextTest)

这在很大程度上是有效的,但是我们看到当有人在 <testheader> 命令周围放置 if 以防止不得不编写 2 个测试用例时,会发生一些奇怪的行为,这两个测试用例仅在header.

经过长时间的考虑,我们决定不允许在 <testheader> 命令周围使用 if,因为只有 <testheader> 不同的情况非常罕见。

所以现在我们要更改实现,使其不再允许 if 围绕 <testheader> 的语句。为此,我们想尝试一种类似于 testcase 的方法,其中在 [=13= 的其余部分之前使用 test_definition(定义 test 关键字)的单独检查] 和 <testbody> 被选中。 (注意:我们必须保持向后兼容,因为 header-sections 周围的 if 几乎从未使用过。

我们尝试的是:

我们认为我们最初将旧 testcommand 分成两部分的方法是正确的,但我们已经为此绞尽脑汁好几天才能让它发挥作用。所以我们最终在这里寻求帮助。

--> 有没有人知道我们如何确保在我们的验证器发现它不是 <testheader> 命令后它会在引发错误之前继续检查 <testbody> 命令?

注意:实现是在 python 2.7 和 pyparsing 2.3.0

中完成的

我的一位同事找到了可行的解决方案。

他还将块拆分为包含所有部分和仅包含测试命令的部分,并将 if 语句中的块部分替换为仅包含测试命令的块。 他还添加了一些额外的解析操作:

    test_command      = NotAny(conditional_construct | eot) - (valid_header_command | valid_test_command | anyotherline)
    no_header_command = NotAny(conditional_construct | eot) - (valid_test_command | anyotherline)

    block = Forward()
    no_header_block = Forward()

    if_statement = (Keyword('if') - vp_expression - eol).addParseAction(self._parseaction_in_if_statement)
    then_block = ZeroOrMore(no_header_block)
    elif_block = Keyword('elif') - vp_expression - eol - ZeroOrMore(no_header_block)
    else_block = Keyword('else') - eol - ZeroOrMore(no_header_block)
    fi_statement = (Keyword('fi') - eol).addParseAction(self._parseaction_out_if_statement)

    conditional_block = if_statement - then_block - ZeroOrMore(elif_block) - Optional(else_block) - fi_statement
    block << ( OneOrMore(test_command) | conditional_block ) # pylint: disable=expression-not-assigned
    no_header_block << ( OneOrMore(no_header_command) | conditional_block ) # pylint: disable=expression-not-assigned