次のフォームを許可するDSLを定義する方法はありますか?
variable identifier identifier variable
例えば:
1 equals to 2
より単純なフォームを作成する方法を知っています: 1 equals to (2)
、しかし、括弧を避けたい. それを行う方法はありますか?
次のフォームを許可するDSLを定義する方法はありますか?
variable identifier identifier variable
例えば:
1 equals to 2
より単純なフォームを作成する方法を知っています: 1 equals to (2)
、しかし、括弧を避けたい. それを行う方法はありますか?
あなたはパーサーに尋ねることができます:
$ 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
…いや、そうではないかもしれません。
私が知る限り、現時点では希望どおりに実装することは不可能です (間違っていることが証明されれば幸いです)。インジェクション用の小さな 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/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
単語インスタンスのみに制限します。
最後の識別子が単項演算子の場合、連続する 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」になります。