Dart支持编写嵌入式DSL吗?

4
我想知道Dart是否能像Groovy一样在运行时执行闭包并支持委托?请参考以下示例以更好地理解:在2小时内从头开始创建Groovy DSL
我用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的东西。


领域特定语言 - 在一个语言中编写代码,而在另一个语言中报告错误 :) - Benjamin Gruenbaum
请您能否详细阐述一下呢? :) 我目前只在小任务中使用DSL。但在考虑将其用于更大的项目之前,也许我需要更加谨慎。是否有任何文章谈论过DSL的缺点? - NagyI
2个回答

5

Dart没有内置的DSL支持。但是,在某些情况下,您可以使用方法级联运算符重载来实现基本的DSL。

对于您的示例,只需要使用方法级联即可。您可以在解析器库Fuzzy Logic库中看到一些好的运算符重载示例。

这是您的代码的方法级联版本:

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,请随意更改为适当的名称。此外,我确定我基于您的代码片段所做的一些结构假设是错误的,但它们应该很容易被更改。

很好,谢谢。虽然它不能满足我所有的标准,但这是一个不错的开始。假设我正在迭代一个集合,该集合在另一个数据结构中保存了作者,并根据此插入“245”数据字段。在Groovy中,我可以在记录定义的中间简单地进行forEach。使用您的定义,我想我的唯一方法是单独创建数据字段定义,然后只是引用它。就像我在Java中所做的那样。这个能否有所改进? - NagyI
@NagyI 噢,我忘记了循环。我们可以比单独的数据字段定义做得更好。我们可以有一个接受数据和创建基于该数据字段的函数的方法,从而避免打破方法级联。我已经编辑了我的帖子,以说明这个例子。缺点是每次想要循环访问某些东西时,都必须创建自定义方法。 - Pixel Elephant
谢谢!看起来这是我们现在可以用Dart做的最接近的事情了。 - NagyI

0
你应该研究一下sweet.js,它为JavaScript提供了卫生宏。你可以编写宏来接受你想要的DSL。编译后,你会得到一个JavaScript文件,你需要将其包含进来。然后你就可以直接从JavaScript或Dart中使用这个DSL了。

3
谢谢。我会查看,但我不喜欢必须混合JavaScript和Dart的想法。如果可能的话,我希望保持纯粹的Dart。 - NagyI

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接