【问题标题】:Does Dart support writing embedded DSLs?Dart 是否支持编写嵌入式 DSL?
【发布时间】:2013-12-18 14:15:26
【问题描述】:

我想知道 Dart 是否能够在运行时通过 Groovy 所具备的这种委托支持来执行闭包?请参阅此示例以更好地理解:A Groovy DSL from scratch in 2 hours

我有一个用 Groovy 编写的 DSL,用于轻松定义 MARC 库记录。我希望能够通过将定义调用绑定到我的程序中的委托类来本地处理类似的 Dart 脚本。

record {
   leader "00000nam a2200000 u 4500"
   controlfield "001", "LIB001"
   controlfield "005", "20120311123453.0"
   datafield("100") {
     subfield "a", "Author of record"
   }
   datafield("245", "0") {
     subfield "a", "Title of record"
   }
}

您可能想知道:为什么这不能用 JSON 表示?有了这样的 DSL,我可以做的不仅仅是表达数据。因为它是嵌入的,所以您可以在 DSL 中做任何在宿主语言中有效的事情(本例是 Groovy)。如果您必须使用不同的值多次定义同一事物,则可以执行 for 循环,您可以使用 GString 表达式、调用数据库、访问文件等。定义 DSLD 后,IDE 就像它一样了解您的概念一直是语言的一部分,它可以为您提供辅助工具。它具有很强的表现力和直观性。

我正在寻找 Dart 类似的东西。

【问题讨论】:

  • 领域特定语言 - 代码以一种语言编写,错误以另一种语言给出:)
  • 您能详细说明一下吗? :) 我目前仅将 DSL 用于小任务。但也许在考虑将它用于更大的东西之前我必须更加小心。有没有文章谈论 DSL 的缺点?

标签: dart dsl


【解决方案1】:

Dart 没有对 DSL 的任何内置支持。不过,在某些情况下,您可以使用method cascadesoperator overloading 来实现基本的DSL。

对于您的示例,只需要方法级联。您可以在 parsers libraryFuzzy Logic library 中看到一些很好的运算符重载示例。

您的代码的方法级联版本可能如下所示:

new Record()
  ..leader = '00000nam a2200000 u 4500'
  ..controlfield('001', 'LIB001')
  ..controlfield('005', '20120311123453.0')
  ..datafield('100', '',
      new Subfield('a', 'Author of record'))
  ..datafield('245', '0',
      new Subfield('a', 'Title of record'));

不能在其中添加循环,但您可以定义接受数据的方法和基于该数据创建字段的函数:

List data = [
               ['a', 'Title of record'],
               ['a', 'Something of record']
              ];
// Same record code from above with the addition of this line:
  ..datafields('245', '', data, (e) => new Subfield(e[0], e[1]));

示例使用以下支持类:

class Record {
  String leader;
  List<ControlField> controlFields = [];
  List<DataField> datafieldList = [];

  void controlfield(String a, String b) {
    controlFields.add(new ControlField(a, b));
  }

  void datafield(String a, String b, Subfield subfield) {
    datafieldList.add(new DataField(a, b, subfield));
  }

  void datafields(String a, String b, Iterable data, Subfield f(E e)) {
    data.forEach( (e) {
      datafieldList.add(new DataField(a, b, f(e)));
    });
  }

}

class ControlField {

  String a;
  String b;

  ControlField(this.a, this.b);
}

class DataField {

  String a;
  String b;
  Subfield subfield;

  DataField(this.a, this.b, this.subfield);
}

class Subfield {

  String a;
  String b;

  Subfield(this.a, this.b);
}

由于我不熟悉 MARC 记录,因此我对所有字段都使用了相当无用的字段名称 a 和 b,请随时将它们更改为适当的名称。此外,我确信我根据您的代码 sn-p 对结构所做的一些假设是错误的,但它们应该很容易更改。

【讨论】:

  • 很好,谢谢。它不能解决我的所有标准,但它是一个好的开始。想象一下,我正在迭代一个集合,该集合将作者保存在另一个数据结构中,并据此插入“245”数据字段。在 Groovy 中,我可以在记录定义的中间简单地做一个 forEach。根据您的定义,我想我唯一的方法是单独创建数据字段定义,然后引用它。就像我会在 Java 中那样做。这可以通过某种方式改进吗?
  • @NagyI 糟糕,我忘记了循环。我们可以做得比单独的数据字段定义好一点。我们可以有一个接受数据的方法和一个基于该数据创建字段的函数,因此我们可以避免打破我们的方法级联。我编辑了我的帖子来说明一个例子。缺点是每次要循环某些内容时都必须创建自定义方法。
  • 谢谢!看起来这是我们现在可以用 Dart 做的最接近的事情了。
【解决方案2】:

您应该查看为 JavaScript 提供卫生宏的 sweet.js。您可以编写宏来接受您想要的 DSL。编译后,您将获得必须包含的 JavaScript 文件。然后你可以直接从 JavaScript 或 Dart 使用 DSL。

【讨论】:

  • 谢谢。我会看一下,但我不喜欢我必须为此混合 Javascript 和 Dart 的想法。如果可能的话,我喜欢保留这个纯粹的 Dart。
猜你喜欢
  • 2012-12-03
  • 1970-01-01
  • 2021-10-14
  • 1970-01-01
  • 2011-06-09
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多