internal domain-specific languages
DESCRIPTION
Internal Domain-Specific Languages. Ras Bodik, Thibaud Hottelier, James Ide UC Berkeley CS164: Introduction to Programming Languages and Compilers Fall 2010. Example internal DSLs. jQuery rfig rake. jQuery. Before jQuery var nodes = document.getElementsByTagName ('a'); - PowerPoint PPT PresentationTRANSCRIPT
1
Internal Domain-Specific Languages
Ras Bodik, Thibaud Hottelier, James IdeUC Berkeley
CS164: Introduction to Programming Languages and Compilers Fall 2010
Example internal DSLs• jQuery• rfig• rake
2
jQueryBefore jQuery
var nodes = document.getElementsByTagName('a'); for (var i = 0; i < nodes.length; i++) { var a = nodes[i]; a.addEventListener('mouseover', function(event)
{ event.target.style.backgroundColor=‘orange'; }, false ); a.addEventListener('mouseout', function(event)
{ event.target.style.backgroundColor=‘white'; }, false ); }
jQuery abstracts iteration and events
jQuery('a').hover( function() { jQuery(this).css('background-color', 'orange'); }, function() { jQuery(this).css('background-color', 'white'); } );
3
rfig
4
rfig: slide authoring DSLEmbedding a domain-specific language (DSL) into Ruby.
see slide 8 in http://cs164fa09.pbworks.com/f/01-rfig-tutorial.pdf
5…
The animation in rfig, a Ruby-based language
slide!('Overlays',
'Using overlays, we can place things on top of each other.', 'The pivot specifies the relative positions', 'that should be used to align the objects in the overlay.',
overlay('0 = 1', hedge.color(red).thickness(2)).pivot(0, 0),
staggeredOverlay(true, # True means that old objects disappear 'the elements', 'in this', 'overlay should be centered',
nil).pivot(0, 0),
cr, pause, # pivot(x, y): -1 = left, 0 = center, +1 = right
staggeredOverlay(true, 'whereas the ones', 'here', 'should be right justified',
nil).pivot(1, 0), nil) { |slide| slide.label('overlay').signature(8) }
rfig was developed by Percy Liang, now a Berkeley student 6
rake
7
rake rake: an internal DSL, embedded in RubyAuthor: Jim Weirich
functionality similar to make– has nice extensions, and flexibility, since it's
embedded– ie can use any ruby commands
even the syntax is close (perhaps better):– embedded in Ruby, so all syntax is legal Ruby
http://martinfowler.com/articles/rake.html8
Example rake filetask :codeGen do # do the code generationend
task :compile => :codeGen do #do the compilationend
task :dataLoad => :codeGen do # load the test dataend
task :test => [:compile, :dataLoad] do # run the testsend 9
How to implement internal DSLs
First, define simple OO programming in 164.
Then we show how to build a jQuery like language
10
Initial OO extensions to 164 def myObj = {} # build an objectmyObj.field = 3myObj.foo = lambda(self, a, b) { print self.field + a }myObj.foo(myObj,1,2)myObj:foo(1,2)
p:foo(x,y) desugars to p.foo(p,x,y)p.foo desugars to p[“foo”] 11
164Query# usage: q('myklass'):fill('ivory2'):font('Helvetica 8')def Q = {} # empty Query objectQ.each = lambda(self,f) { for (n in preorder(window)) { if ("klass" in n) { if (n.klass == self.klass) { f(n) } } } # return the query object to allow call chaining self}def q(clss) { def query = copy(Q) query.klass=clss query}
12
ContinuedQ.fill = lambda(self,color) { self:each(lambda(node) { node.fill = color }) }
Q.font = lambda(self,font) { self:each(lambda(node) { for (n in preorder(node)) { if (n:class() == Word) { n.font = font } } })}
13
Example rake filetask :codeGen do # do the code generationend
task :compile => :codeGen do #do the compilationend
task :dataLoad => :codeGen do # load the test dataend
task :test => [:compile, :dataLoad] do # run the testsend 14
How is rake legal ruby?Deconstructing rake (teaches us a lot about
Ruby):
task :dataLoad => :codeGen do # load the test dataend
task :test => [:compile, :dataLoad] do # run the testsend
15
Two kinds of tasksFile task: dependences between files (like in
main)file 'build/dev/rake.html' => 'dev/rake.xml' do |t|
require 'paper' maker = PaperMaker.new t.prerequisites[0], t.name
maker.runend
16
Two kinds of tasksRake task: dependences between jobs
task :build_refact => [:clean] do target = SITE_DIR + 'refact/' mkdir_p target, QUIET require 'refactoringHome' OutputCapturer.new.run {run_refactoring}end
17
Orthogonalize dependences and rulestask :second do #second's bodyend
task :first do #first's bodyendtask :second => :first
18
General rulesSort of like make's %.c : %.c
BLIKI = build('bliki/index.html')
FileList['bliki/*.xml'].each do |src|file BLIKI => src
end
file BLIKI do #code to build the blikiend
19