Scala中的内部DSL:没有“,”的列表
发布时间:2020-12-16 18:25:31 所属栏目:安全 来源:网络整理
导读:我正在尝试在 Scala中构建一个内部DSL来表示代数定义.让我们考虑一下这个简化的数据模型: case class Var(name:String)case class Eq(head:Var,body:Var*)case class Definition(name:String,body:Eq*) 例如,一个简单的定义是: val x = Var("x")val y = Va
我正在尝试在
Scala中构建一个内部DSL来表示代数定义.让我们考虑一下这个简化的数据模型:
case class Var(name:String) case class Eq(head:Var,body:Var*) case class Definition(name:String,body:Eq*) 例如,一个简单的定义是: val x = Var("x") val y = Var("y") val z = Var("z") val eq1 = Eq(x,y,z) val eq2 = Eq(y,x,z) val defn = Definition("Dummy",eq1,eq2) 我希望有一个内部DSL来表示以下形式的等式: Dummy { x = y z y = x z } 我能得到的最接近的是: Definition("Dummy") := ( "x" -> ("y","z") "y" -> ("x","z") ) 我遇到的第一个问题是我不能对Definition和Var进行两次隐式转换,因此定义(“Dummy”).然而,主要问题是清单.我不想用任何东西包围它们,例如(),我也不希望它们的元素用逗号分隔. 我想要什么可能使用Scala?如果是的话,有人能告诉我一个简单的方法吗? 解决方法
虽然Scalas语法功能强大,但它不够灵活,无法为符号创建任意分隔符.因此,没有办法留下逗号并仅用空格替换它们.
然而,可以使用宏并在编译时解析具有任意内容的字符串.它不是一个“简单”的解决方案,而是一个有效的解决方案: object AlgDefDSL { import language.experimental.macros import scala.reflect.macros.Context implicit class DefDSL(sc: StringContext) { def dsl(): Definition = macro __dsl_impl } def __dsl_impl(c: Context)(): c.Expr[Definition] = { import c.universe._ val defn = c.prefix.tree match { case Apply(_,List(Apply(_,List(Literal(Constant(s: String)))))) => def toAST[A : TypeTag](xs: Tree*): Tree = Apply( Select(Ident(typeOf[A].typeSymbol.companionSymbol),newTermName("apply")),xs.toList ) def toVarAST(varObj: Var) = toAST[Var](c.literal(varObj.name).tree) def toEqAST(eqObj: Eq) = toAST[Eq]((eqObj.head +: eqObj.body).map(toVarAST(_)): _*) def toDefAST(defObj: Definition) = toAST[Definition](c.literal(defObj.name).tree +: defObj.body.map(toEqAST(_)): _*) parsers.parse(s) match { case parsers.Success(defn,_) => toDefAST(defn) case parsers.NoSuccess(msg,_) => c.abort(c.enclosingPosition,msg) } } c.Expr(defn) } import scala.util.parsing.combinator.JavaTokenParsers private object parsers extends JavaTokenParsers { override val whiteSpace = "[ t]*".r lazy val newlines = opt(rep("n")) lazy val varP = "[a-z]+".r ^^ Var lazy val eqP = (varP <~ "=") ~ rep(varP) ^^ { case lhs ~ rhs => Eq(lhs,rhs: _*) } lazy val defHead = newlines ~> ("[a-zA-Z]+".r <~ "{") <~ newlines lazy val defBody = rep(eqP <~ rep("n")) lazy val defEnd = "}" ~ newlines lazy val defP = defHead ~ defBody <~ defEnd ^^ { case name ~ eqs => Definition(name,eqs: _*) } def parse(s: String) = parseAll(defP,s) } case class Var(name: String) case class Eq(head: Var,body: Var*) case class Definition(name: String,body: Eq*) } 它可以用于这样的事情: scala> import AlgDefDSL._ import AlgDefDSL._ scala> dsl""" | Dummy { | x = y z | y = x z | } | """ res12: AlgDefDSL.Definition = Definition(Dummy,WrappedArray(Eq(Var(x),WrappedArray(Var(y),Var(z))),Eq(Var(y),WrappedArray(Var(x),Var(z))))) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |