8

次のフォームを許可するDSLを定義する方法はありますか?

variable identifier identifier variable

例えば:

1 equals to 2

より単純なフォームを作成する方法を知っています: 1 equals to (2)、しかし、括弧を避けたい. それを行う方法はありますか?

4

3 に答える 3

13

あなたはパーサーに尋ねることができます:

$ scala -Xprint:parser
Welcome to Scala version 2.9.2 ... blah

scala> variable1 identifier1 identifier2 variable2
// lots of stuff and inside:
val res0 = variable1.identifier1(identifier2).variable2
// this is how the parser sees it.
// if you can make that work (dynamic classes…?), you’re good to go.

ただし、問題があります。これvariable2は、識別子である場合にのみ機能します(メソッド名として使用できるようにするため)。と

scala> 1 equals to 2

すでにパーサーは失敗します:

<console>:1: error: ';' expected but integer literal found.
       1 equals to 2
                   ^

かっこは本当にあなたの唯一の方法です(*):

scala> 1 equals to (2)
// ...
val res1 = 1.equals(to(2))

(*)2バックティックで使用して識別子を作成しない限り

scala> 1 equals to `2`
// ...
val res2 = 1.equals(to).2

…いや、そうではないかもしれません。

于 2012-05-08T19:21:22.340 に答える
3

私が知る限り、現時点では希望どおりに実装することは不可能です (間違っていることが証明されれば幸いです)。インジェクション用の小さな DSL を作成していたときにも、この問題に直面しました。しかし、2 つの識別子の間に 2 つの変数を持つことができなくても、それらの間に 3 つの識別子を持つことができることに気付きました。次のようになります。

variable1 method constant method variable2

これは次と同じです:

variable1.method(constant).method(variable2)

これにより、次のような非常に優れた DSL を思いつくことができました。

by default defaultDb and identified by 'remote
'remote is by default defaultDb

この仕様で、その使用例をさらに見つけることができます。

https://github.com/OlegIlyenko/scaldi/blob/48f7e4186cf7eb441116087003d7f45f16e0ac6c/src/test/scala/scaldi/InjectableSpec.scala#L47

その実装は次の場所にあります。

https://github.com/OlegIlyenko/scaldi/blob/master/src/main/scala/scaldi/Injectable.scala

メソッドの引数としてByWordとクラス型を使用しました。IdentifiedWord例えば:

def is(by: ByWord) = and(by)

これにより、ライブラリのユーザーがByWorldクラスを拡張し、一般に独自のByWorld実装を提供できる可能性が残ります。今考えると、これはあまりいいことではないと思います。より良い解決策は、定数単語のシングルトン オブジェクトを作成し、その型を次のように使用することです。

object by
def is(byWord: by.type) = and(by)

これは通常、引数を 1 つの可能なby単語インスタンスのみに制限します。

于 2012-05-08T19:42:17.400 に答える
1

単項演算子

最後の識別子が単項演算子の場合、連続する 2 つの識別子を持つことができます。

a identifier1 - d

として解析されます

a.identifier1(d.unary_-)

単項関数は ! 〜と〜

動的メソッド

最後の変数名を文字列として処理しても構わない場合 (たとえば、後でマップまたはインタープリター自体からその値を取得する方法がある場合)、ダイナミクスを使用して次のようにすることができます。

import scala.Dynamic
import scala.language.dynamics

class I2
class Res(i: I2) extends Dynamic {
  def selectDynamic(obj: String): Unit = {
      println(obj)
    }
}
class V1 { def i1(i2: I2): Res= new Res(i2) }
val v1 = new V1
val i2 = new I2

v1 i1 i2 v2

文字列「v2」になります。

于 2013-12-21T14:52:20.917 に答える