-
-
Save gokepler/8dd390e6038236268f28c523c65e15d0 to your computer and use it in GitHub Desktop.
领域专用语言实战
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
领域专用语言实战 | |
跳转至: 导航、 搜索 | |
目录 | |
1 初识DSL | |
2 现实中的DSL | |
3 DSL驱动的应用程序开发 | |
4 内部DSL实现模式 | |
5 Ruby、Groovy、Clojure语言中的内部DSL设计 | |
6 Scala语言中的内部DSL设计 | |
7 外部DSL的实现载体 | |
8 用Scala语法解析器组合子设计外部DSL | |
9 展望DSL设计的未来 | |
10 附录A:抽象在领域建模中的角色 | |
11 附录B:元编程与DSL设计 | |
12 附录C:Ruby语言的DSL相关特性 | |
13 附录D:Scala语言的DSL相关特性 | |
14 附录E:Groovy语言的DSL相关特性 | |
15 附录F:Clojure语言的DSL相关特性 | |
16 附录G:多语言开发 | |
初识DSL | |
现实中的DSL | |
Groovy方案: | |
newOrder.to.buy(100.shares.of('IBM')){ | |
limitPrice 300 | |
allOrNone true | |
valueAs {qty, unitPrice -> qty * unitPrice - 500} | |
实现: | |
methodMissing | |
Integer.metaClass.getShares = { -> delegate } //? | |
closure参数? | |
内部DSL实现手段 | |
灵巧API | |
Guice例:binder.bind(Service.class).to(ServiceImpl.class).in(Scopes.SINGETON) | |
语法树(AST)操纵 | |
类型化内嵌 | |
Paul Hudak, 1998 Haskell | |
反射式元编程 | |
Ruby Object#send() | |
运行时元编程 | |
例:Rails(ActiveRecord?has_many belongs_to validates_xxx_of) | |
编译时元编程 | |
LISP/Clojure宏、C宏、C++模板 | |
外部DSL实现手段 | |
简单的正则表达式替换,代码生成 | |
XML | |
Xtext | |
Scala解析器组合子 | |
DSL驱动的应用程序开发 | |
new ScriptEngineManager().getEngineByName("groovy").eval( ... new SequenceInputStream(...)... ); //cast to List<?> | |
由于DSL脚本被一个单独的ClassLoader加载,与Java环境存在互操作问题 | |
用Scala作为Java的包装器集成(GroovyClassLoader?) | |
p55 implicit def enrichAccount(acc: Account): AccountDSL = new AccountDSL(acc) | |
注意:implicit限制了词法作用域! | |
p57 accounts.filter(_ belongsTo "John S.").map(_.caclcInterest).filter(_>threshold).foldLeft(0.0)(_+_) | |
基于Spring 2.0+的集成* | |
内部DSL实现模式 | |
装饰器 | |
class TaxFeeDecorator extends Trade { ... } | |
Ruby例: | |
def with(*args) | |
args.inject(self) { |memo, val| memo.extend val } | |
yield self if block_given? | |
tr = Trade.new(...).with TaxFee, Commision (混入2个module!) | |
Groovy ObjectGraphBuilder? | |
ClassNameResolver* | |
Scala泛型groupBy | |
def groupBy[T <% Ordered[T]](f: TradedQuantity => T) = { | |
val m = new HashMap[T, Set[TradedQuantity ]] with MultiMap[T, TradedQuantity] | |
for( q <- quantities) m.addBinding (f(q), q) | |
m.keys.toList.sort(_<_).map( m.andThen(_.toList)) 靠 | |
p94 类型化约束 trait Trade { | |
type A <: Trading | |
val account: A | |
生成式DSL:通过模板 | |
Ruby:类方法、mixin | |
生成式DSL:通过宏 | |
(defmacro with-account [acc & body] | |
`(cond | |
(nil? ~acc) (throw (IllegalArgumentException. "error1")) | |
(= (trading? ~acc) false) (throw (IllegalArgumentException. "error2")) | |
:else ~@body)) | |
Ruby、Groovy、Clojure语言中的内部DSL设计 | |
鸭子类型 | |
p111 Groovy MOP? | |
CLojure类型提示(type hint)? | |
猴子补丁(Ruby开放类) | |
p124 Groovy知识点* | |
ExpandoMetaClass | |
closure和delegate | |
Category? | |
p132 redef | |
Scala语言中的内部DSL设计 | |
trait | |
p149 只要用户定义好转换(implicit),Scala会在脚本的调用点插入必要的语义结构(.) | |
偏函数 | |
val f: PartialFunction[Boolean, Int] = { case true => 100 } | |
模块(object) | |
map、foldLeft、foldRight | |
p172 Monad | |
unit | |
bind(flatMap -> for语法糖) | |
外部DSL的实现载体 | |
表7.1 YACC/Lex Bison/Flex Antlr Coco/R JavaCC* Jikes* | |
p192 递归下降回溯分析器 PEG | |
记忆分析器(Packrat) | |
语义谓词分析器* | |
p194 Xtext | |
元模型?EString Eint ...(可以生成IDE插件??牛) | |
生成代码:Xpand模板 ? | |
用Scala语法解析器组合子设计外部DSL | |
常用的解析器组合子: | |
顺序 ~ | |
选择性顺序 ~> <~ | |
替代 | | |
函数应用 ^^ ^^^ | |
p ^^ f | |
p ^^^ r(生成AST的叶子节点?) | |
p ^? (f, error) | |
重复 | |
rep(p), p* | |
rep1(p), p+ | |
repN(n,p) | |
rep1sep(p,sep), p+(sep) | |
p207 Newspeak语言:Self+SmallTalk? | |
包scala.util.parsing | |
abstract class Parser[+T] extends (Input => ParserResult[T]) | |
sealed abstract class ParserResult[+T] { ... var next: Input } //跟踪下一个输入? | |
Success | |
Failure | |
object OrderDsl extends StandardTokenParsers { //import scala.util.parsing.combinator.syntactical._ | |
lexical.reserved += ("to", "buy", ...) | |
lexical.delimiters += ("(", ")", ",") | |
lazy val order = items ~ account_spec | |
lazy val items = "(" ~> rep1sep(line_item, ",") <~ ")" | |
... | |
用Monad组合DSL分析器 | |
def ~ [U](p: => Parser[U]): Parser[~[T,U]] = (for(a <- this; b <- p) yield new ~(a,b)).named("~") | |
LL(k)语法的packrat分析 | |
通过使用一个带缓存能力的Reader:class PackratReader[+T](underlying: Reader[T]) extends Reader[T] { ... } | |
?packrat提供无扫描器的语法分析? | |
但:为了区分保留字和标识符,需要为文法补充一些作为消除歧义的额外信息 | |
如果几个备选项开头部分有重合,应将匹配长度较长的备选项排在前面 | |
SSI(结算常设规则?):用于指示特定交易应该在什么帐号上结算 | |
p227~228 这个地方的代码例子有点复杂,跳过 | |
p226 把分析器转为packrat的步骤:? | |
mixin PackratParsers(with语法) | |
给出Reader[Elem]的具体类型,作为对Input的定义 | |
显式指定返回类型为PackratParser[...] | |
展望DSL设计的未来 | |
p238 DSL工作台 | |
Eclipse EMF | |
MPS | |
DSL版本化* | |
附录A:抽象在领域建模中的角色 | |
作者多次强调,Scala的implicits比Ruby的monkey patching更好? | |
基于原型的OO | |
分离命令和查询* | |
STM* | |
附录B:元编程与DSL设计 | |
附录C:Ruby语言的DSL相关特性 | |
附录D:Scala语言的DSL相关特性 | |
附录E:Groovy语言的DSL相关特性 | |
附录F:Clojure语言的DSL相关特性 | |
附录G:多语言开发 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment