【问题标题】:Indenting for code-generation代码生成缩进
【发布时间】:2010-09-18 01:13:49
【问题描述】:

通常,程序员编写的代码会生成其他代码。

(技术术语是metaprogramming,但它比单纯的交叉编译器更常见;想想每个生成 HTML 的 PHP 网页或每个 XSLT 文件。)

我认为具有挑战性的一个领域是提出技术以确保手写源文件和计算机生成的目标文件都清楚地缩进以帮助调试。这两个目标似乎经常相互竞争。

我发现这在 PHP/HTML 组合中特别具有挑战性。我认为这是因为:

  • 有时源文件中的 HTML 代码比生成的 PHP 代码多
  • HTML 文件往往比 SQL 语句长,需要更好的缩进
  • HTML 具有空间敏感特性(例如标签之间)
  • 结果是 HTML 比 SQL 语句更公开可见,因此做合理工作的压力更大。

您使用什么技术来解决这个问题?


编辑:我接受至少有三个论点不费心生成漂亮的 HTML 代码:
  • 增加了生成代码的复杂性。
  • 与浏览器渲染没有区别;开发者可以使用 Firebug 或类似的工具来很好地查看它。
  • 轻微的性能损失 - 增加了空白字符的下载时间。

我确实有时会生成代码而不考虑缩进(尤其是 SQL)。

但是,也有一些反对意见:

  • 我发现,在实践中,我确实经常阅读生成的代码 - 有额外的步骤来访问它很不方便。
  • HTML 有时会遇到一些空间敏感问题。

例如,考虑代码:

<div class="foo">
    <?php
        $fooHeader();
        $fooBody();
        $fooFooter();
    ?>
</div>

比下面的代码更清晰:

<div class="foo"><?php
        $fooHeader();
        $fooBody();
        $fooFooter();
?></div>

但是,由于 HTML 中包含空白,它也有不同的渲染。

【问题讨论】:

  • 为什么不使用代码格式化程序?这解决了所有这些问题。

标签: php code-generation metaprogramming


【解决方案1】:

当生成代码支配生成代码时,我使用的一种技术是传递一个缩进参数。

例如,在 Python 中,生成更多 Python。

def generateWhileLoop(condition, block, indentPrefix = ""):
    print indentPrefix + "while " + condition + ":"
    generateBlock(block, indentPrefix + "    ")

或者,取决于我的心情:

def generateWhileLoop(condition, block, indentLevel = 0):
    print " " * (indentLevel * spacesPerIndent) + "while " + condition + ":"
    generateBlock(block, indentLevel + 1)

请注意假设condition 是一小段文本,可以放在同一行,而block 是在单独的缩进行上。如果这段代码不能确定子项是否需要缩进,这个方法就开始掉线了。

此外,这种技术对于将相对少量的 PHP 散布到 HTML 中几乎没有那么有用。

[编辑澄清:我写了这个问题和这个答案。我想用一种我确实使用过并且有时很有用的技术来寻找答案,但是这种技术在典型的 PHP 编码中失败了,所以我正在寻找其他类似的想法。]

【讨论】:

  • 如果您正在组装文本块而不是单行,则此解决方案效果不佳。
  • 在示例代码中,我展示了单行如何工作(例如 condition)和块如何工作(例如 block)。当您不知道自己在期待什么时,它就无法正常工作。
  • 我做过类似的事情,只是我通过将它包装在一个类中来清理它。我会有类似带有缩进计数器的 IndentedOutput 类。然后我对上面的调用看起来像:out.line("while " + condition + ":"), out.indent(), generateBlock(...), out.unndent()
【解决方案2】:

在更一般的情况下,我编写了生成 C++ 数据库接口代码的 XSLT 代码。虽然一开始我试图从 XSLT 输出正确缩进的代码,但这很快就变得站不住脚了。我的解决方案是完全忽略 XSLT 输出中的格式,然后通过GNU indent 运行生成的非常长的代码行。这产生了一个格式合理的适合调试的 C++ 源文件。

我可以想象,在处理 HTML 和 PHP 等组合源时,问题会变得更加棘手。

【讨论】:

  • 这涉及 C++,但该帖子的作者特别提到了 PHP 和 HTML。作为一个普通的 PHP 程序员,我觉得这个问题很烦人,尤其是在格式化数组时(Ruby 也有这个问题)。这个具体案例的答案是什么?
  • @American Yak:我不知道。 PHP 是否有等价于indent
【解决方案3】:

生成一个 AST,然后按顺序遍历它并发出格式正确的源代码。

【讨论】:

【解决方案4】:

我同意奇思妙想的回答。

有时最好通过反转来解决问题。如果您发现自己生成了大量文本,请考虑使用少量智能生成代码将文本编写为模板是否更容易。或者,如果您可以将问题分解为一系列您组装的小模板,然后将每个模板作为一个整体缩进。

【讨论】:

    【解决方案5】:

    在 PHP 中制作网站时,我发现混合使用 HTML 和特定功能的 PHP 存在问题,它限制了概述并使调试更加困难。在这种情况下避免混合的解决方案是使用模板驱动的内容,例如see Smarty。除了更好的意图之外,内容模板对于其他事情也很有用,例如更快的修补。如果客户需要更改布局,则可以快速找到并修复该特定布局问题,而无需使用生成数据的功能性 PHP 代码(反之亦然)。

    【讨论】:

      【解决方案6】:

      特别是关于 HTML 生成 - 为什么它很重要?

      您花费大量时间传递缩进参数,并试图弄清楚您的嵌套深度等等。除了一般浪费时间(因为最终渲染没有区别输出),当您添加其他 HTML 标记并将页面包装在 div 等中时,您如何维护所有这些内容?

      无论如何,安装Firebug(和IE developer toolbar 用于之后测试IE),它们都会以嵌套格式向您显示HTML,您只需单击页面元素即可直接查看标记 - 方式比查看原始源 HTML 输出。

      【讨论】:

        【解决方案7】:

        我发现在生成过程中忽略缩进是最好的。我编写了一个通用的“代码格式化”引擎,可以对所有输出的代码进行后处理。这样,我可以与生成器分开定义缩进规则和代码语法规则。这种分离有明显的好处。

        【讨论】:

          【解决方案8】:

          在 PHP/HTML 的情况下,我尝试让每个代码片段在其源代码中始终缩进。这使代码在真正重要的地方保持可读性,并且通常具有产生可读的 HTML 输出的副作用。正如其他人所说,萤火虫会处理其余的事情。

          【讨论】:

            猜你喜欢
            • 2015-05-14
            • 2011-12-07
            • 2014-03-27
            • 1970-01-01
            • 2022-07-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多