SlideShare a Scribd company logo
Implementing External DSLs Using Scala Parser Combinators St. Louis Lambda Lounge Sept. 3, 2009 Tim Dalton Senior Software Engineer Object Computing Inc.
External vs Internal DSL Internal DSLs are implemented using syntax of “host” programming language Examples Fluent APIs in Java RSpec and ScalaSpec Constrained by features of programming language External DSLs syntax is only limited by capabilities of the parser
What is a Combinator ? Combinators are functions that can be combined to perform more complex operations Concept originates in Lambda Calculus Mostly comes from the Haskell community Haskell implementations use Monads Scala implementation “almost Monadic”
Scala’s Parser Implementation Context-free LL grammar Left to right Leftmost derivation  Recursive descent Backtracking There are ways to prevent backtracking Advances planned for Scala 2.8 Support for Packrat parsing  Parser Expression Grammar More predictive with less recursion and backtracking
Scala Combinator Parser Hierarchy scala.util.parsing.combinator.Parsers scala.util.parsing.combinator.syntactical.TokenParsers scala.util.parsing.combinator.syntactical.StdTokenParsers scala.util.parsing.combinator.RegexParsers scala.util.parsing.combinator.JavaTokenParsers
A Simple Logo(-Like) Interpreter Only a few commands: Right Turn <angle-degrees>  Left Turn <angle-degrees> Forward <number-of-pixels> Repeat <nested sequence of other commands>
Grammar for Simple Logo forward = (“FORWARD” | “FD”) positive-integer right = (“RIGHT” | “RT) positive-integer left = (“LEFT” | “LT”) positive-integer repeat = “REPEAT” positive-integer “[“{statement}”]” statement = right | left | forward | repeat program = { statement }
Scala Code to Implement Parser object LogoParser extends RegexParsers { def positiveInteger = &quot;&quot;&quot;\d+&quot;&quot;&quot;r def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~positiveInteger  def right = (&quot;RT&quot;|&quot;RIGHT&quot;)~positiveInteger  def left = (&quot;LT&quot;|&quot;LEFT&quot;)~positiveInteger  def repeat = &quot;REPEAT&quot; ~ positiveInteger ~ &quot;[&quot; ~ rep(statement) ~ &quot;]&quot;  def statement:Parser[Any] = forward | right | left | repeat def program = rep(statement) }
Scala Code to Implement Parser An internal DSL is used to implement an External One Methods on preceding slide are referred to as  parser generators RegexParsers is subclass of Parsers trait that provides a generic parser combinator
A Closer Look def positiveInteger = &quot;&quot;&quot;\d+&quot;&quot;&quot;r The trailing “r” is a method call the converts the string to a Regex object More verbose syntax: &quot;&quot;&quot;\d+&quot;&quot;&quot;.r() String does not have an r() method !! Class RichString does, so an  implicit conversion  is done
Implicit Conversions One of the more powerful / dangerous features of Scala is implicit conversions RichString.r method signature def  r  : Regex   scala.Predef implicit convertor implicit def stringWrapper( x  : java.lang.String) : RichString   The Scala compiler will look for implicit convertors in scope and insert them implicitly “ With great power, comes great responsibility”
Back to the Parser def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~positiveInteger   The “|” and “~” are methods of class Parsers.Parser[T] !! RegexParser has implicit conversions: implicit def literal(s : String) : Parser[String]  implicit def regex(r : Regex) : Parser[String]   Parser generator methods should return something that can be at least be converted to Parser[T]
Parser[T]’s and ParseResult[T]’s Parsers.Parser[T] Extends Reader => ParseResult[T] This makes it a function object  ParserResult[T] Hierarchy: Parsers.Success Parsers.NoSuccess Parsers.Failure Parsers.Error Invoking Parsers[T] function object return one of the above subclasses
Combining Parser[T]’s Signature for Parser[T].| method: def |[U >: T](q : => Parser[U]) : Parser[U]   Parser Combinator for alternative composition (OR) Succeeds (returns Parsers.Success) if either “this” Parser[T] succeeds or “q” Parser[U] succeeds Type U must be same or super-class of type T.
Combining Parser[T]’s Signature of Parser[T].~ method: def ~[U](p : => Parser[U]) : Parser[~[T, U]] Parser Combinator for sequential composition  Succeeds only if “this” Parser succeeds and “q” Parser succeeds Return an instance “~” that contain both results Yes, “~” is also a class ! Like a Pair, but easier to pattern match on
Forward March Back to the specification of forward: def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~positiveInteger   For this combinator to succeed,  Either the Parser for literal “FD” or “FORWARD” And the Parser for the positiveInt Regex Both the literal strings and Regex result of positiveInt are implicitly converted to Parser[String]
Repetition Next lines of note: def repeat = &quot;REPEAT&quot; ~ positiveInteger ~ &quot;[&quot; ~ rep(statement) ~ &quot;]&quot;  def statement:Parser[Any] =    forward | right | left | repeat Type for either repeat or statement need to be explicitly specified due to recursion The rep method specifies that Parser can be repeated
Repetition Signature for Parsers.rep method: def  rep[T](p : => Parser[T]) : Parser[List[T]]   Parser Combinator for repetitions Parses input until Parser, p, fails. Returns consecutive successful results as List.
Other Forms of Repetition def repsep[T](p: => Parser[T], q: => Parser[Any]) : Parser[List[T]] Specifies a Parser to be interleaved in the repetition Example:  repsep(term, &quot;,&quot;)  def rep1[T](p: => Parser[T]): Parser[List[T]] Parses non-empty repetitions def  repN[T](n : Int, p : => Parser[T]) : Parser[List[T]]   Parses a specified number of repetitions
Execution Root Parser Generator: def program = rep(statement)   To Execute the Parser parseAll(program, &quot;REPEAT 4 [FD 100 RT 90]&quot;) Returns Parsers.Success[List[Parsers.~[…]]] Remember ,Parsers.Success[T] is subclass of ParseResult[T] toString: [1.24] parsed: List(((((REPEAT~4)~[)~List((FD~100), (RT~90)))~])) The “…” indicates many levels nested Parsers
Not-so-Happy Path Example of failed Parsing: parseAll(program, &quot;REPEAT 4 [FD 100 RT 90 ) &quot;) Returns Parsers.Failure Subclass of ParseResult[Nothing] toString: [1.23] failure: `]' expected but `)' found REPEAT 4 [FD 100 RT 90) ^ Failure message not always so “precise”
Making Something Useful Successful parse results need to transformed into something that can be evaluated Enter the “eye brows” method of Parser[T]: def  ^^[U](f : (T) => U) : Parser[U]   Parser combinator for function application
Eye Brows Example Example of “^^” method: def positiveInteger = &quot;&quot;&quot;\d+&quot;&quot;&quot;.r ^^  { x:String => x.toInt } Now positiveInteger generates Parser[Int] instead of Parser[String] Transformer can be shortened to  “{ _.toInt }”
Implementing Commands For the statements we need a hierarchy of command classes: sealed abstract class LogoCommand case class Forward(x: Int) extends LogoCommand case class Turn(x: Int) extends LogoCommand case class Repeat(i: Int, e: List[LogoCommand]) extends LogoCommand
Transforming into Commands The Forward command: def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~positiveInteger  ^^  { case _~value => Forward(value) } A ~[String, Int] is being passed in the transformer Pattern matching is to extract the Int, value and construct a Forward instance Forward is a case class, so “new” not needed Case constructs can be partial functions themselves. Longer form: … ^^ { tilde => tilde match  { case _~value => Forward(value) }}
Derivates of “~” Two methods related to “~”: def <~  [U](p: => Parser[U]): Parser[T] Parser combinator for sequential composition which keeps only the left result  def  ~>  [U](p: => Parser[U]): Parser[U]  Parser combinator for sequential composition which keeps only the right result  Note, neither returns a “~” instance The forward method can be simplified: def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~>positiveInteger ^^  { Forward(_) }
Updated Parser def positiveInteger = &quot;&quot;&quot;\d+&quot;&quot;&quot;.r ^^  { _.toInt } def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~>positiveInteger  ^^  { Forward(_) } def right = (&quot;RT&quot;|&quot;RIGHT&quot;)~>positiveInteger ^^  { x => Turn(-x) } def left = (&quot;LT&quot;|&quot;LEFT&quot;)~>positiveInteger ^^  { Turn(_) } def repeat = &quot;REPEAT&quot; ~> positiveInteger ~ &quot;[&quot; ~ rep(statement) <~ &quot;]&quot; ^^ { case number~_~statements => Repeat(number, statements)}
Updated Parser Results Executing the Parser now: parseAll(program, &quot;REPEAT 4 [FD 100 RT 90]&quot;) Results: [1.24] parsed: List(Repeat(4,List(Forward(100), Turn(-90)))) Returns Parsers.Success[List[Repeat]] This can be evaluated !!
Evaluation class LogoEvaluationState { var x = 0 var y = 0 var heading = 0 } implicit def dblToInt(d: Double):Int = if (d > 0) (d+0.5).toInt else (d-0.5).toInt def parse(s: String) : List[LogoCommand] = LogoParser.parse(s).get def evaluate(parseResult: LogoParser.ParseResult[List[LogoCommand]], g:Graphics2D) { var state = new LogoEvaluationState if (parseResult.successful) { evaluate(parseResult.get, g, state) } // draw turtle evaluate(parse(&quot;RT 90 FD 3 LT 110 FD 10 LT 140 FD 10 LT 110 FD 3&quot;),  g, state) } // Continued...
Evaluation (More Functional) private def evaluate(list: List[LogoCommand], g:Graphics2D, state:LogoEvaluationState) {  if (!list.isEmpty) { val head :: tail = list head match {   case Forward(distance) => { val (nextX, nextY) =  (state.x + distance * sin(toRadians(state.heading)),   state.y + distance * cos(toRadians(state.heading))) g.drawLine(state.x, state.y, nextX, nextY) state.x = nextX state.y = nextY evaluate(tail, g, state)   }   case Turn(degrees) => { state.heading += degrees evaluate(tail, g, state)   }   case Repeat(0, _) => evaluate(tail, g, state)   case Repeat(count, statements) =>  evaluate(statements ::: Repeat(count-1, statements)::tail, g, state) } } }
Evaluation (More Imperative) def evaluate(list: List[LogoCommand], g:Graphics2D, state:LogoEvaluationState) { list.foreach(evaluate(_, g, state)) } def evaluate(command:LogoCommand, g:Graphics2D, state:LogoEvaluationState) { command match {   case Forward(distance) => {     val (nextX, nextY) = (state.x + distance *  Math.sin(Math.toRadians(state.heading)), state.y + distance *  Math.cos(Math.toRadians(state.heading))) g.drawLine(state.x, state.y, nextX, nextY) state.x = nextX state.y = nextY   }   case Turn(degrees) => state.heading += degrees   case Repeat(count, statements) => (0 to count).foreach { _ => evaluate(statements, g, state)     }   } }
Demonstration
Ad

More Related Content

What's hot (19)

Topdown parsing
Topdown parsingTopdown parsing
Topdown parsing
Antony Alex
 
Functions
FunctionsFunctions
Functions
PatriciaPabalan
 
Ch2
Ch2Ch2
Ch2
kinnarshah8888
 
Ch4a
Ch4aCh4a
Ch4a
kinnarshah8888
 
Operator precedence
Operator precedenceOperator precedence
Operator precedence
Akshaya Arunan
 
Types of Parser
Types of ParserTypes of Parser
Types of Parser
SomnathMore3
 
Quicksort Presentation
Quicksort PresentationQuicksort Presentation
Quicksort Presentation
irdginfo
 
Module 11
Module 11Module 11
Module 11
bittudavis
 
Top Down Parsing, Predictive Parsing
Top Down Parsing, Predictive ParsingTop Down Parsing, Predictive Parsing
Top Down Parsing, Predictive Parsing
Tanzeela_Hussain
 
Nonrecursive predictive parsing
Nonrecursive predictive parsingNonrecursive predictive parsing
Nonrecursive predictive parsing
alldesign
 
Recursive descent parsing
Recursive descent parsingRecursive descent parsing
Recursive descent parsing
Boy Baukema
 
Parsing
ParsingParsing
Parsing
ShrikantSharma86
 
Left factor put
Left factor putLeft factor put
Left factor put
siet_pradeep18
 
Parsing in Compiler Design
Parsing in Compiler DesignParsing in Compiler Design
Parsing in Compiler Design
Akhil Kaushik
 
Python (regular expression)
Python (regular expression)Python (regular expression)
Python (regular expression)
Chirag Shetty
 
Bottom up parser
Bottom up parserBottom up parser
Bottom up parser
Akshaya Arunan
 
Control Structures in C
Control Structures in CControl Structures in C
Control Structures in C
sana shaikh
 
Theory of automata and formal language lab manual
Theory of automata and formal language lab manualTheory of automata and formal language lab manual
Theory of automata and formal language lab manual
Nitesh Dubey
 
Top down and botttom up Parsing
Top down     and botttom up ParsingTop down     and botttom up Parsing
Top down and botttom up Parsing
Gerwin Ocsena
 
Quicksort Presentation
Quicksort PresentationQuicksort Presentation
Quicksort Presentation
irdginfo
 
Top Down Parsing, Predictive Parsing
Top Down Parsing, Predictive ParsingTop Down Parsing, Predictive Parsing
Top Down Parsing, Predictive Parsing
Tanzeela_Hussain
 
Nonrecursive predictive parsing
Nonrecursive predictive parsingNonrecursive predictive parsing
Nonrecursive predictive parsing
alldesign
 
Recursive descent parsing
Recursive descent parsingRecursive descent parsing
Recursive descent parsing
Boy Baukema
 
Parsing in Compiler Design
Parsing in Compiler DesignParsing in Compiler Design
Parsing in Compiler Design
Akhil Kaushik
 
Python (regular expression)
Python (regular expression)Python (regular expression)
Python (regular expression)
Chirag Shetty
 
Control Structures in C
Control Structures in CControl Structures in C
Control Structures in C
sana shaikh
 
Theory of automata and formal language lab manual
Theory of automata and formal language lab manualTheory of automata and formal language lab manual
Theory of automata and formal language lab manual
Nitesh Dubey
 
Top down and botttom up Parsing
Top down     and botttom up ParsingTop down     and botttom up Parsing
Top down and botttom up Parsing
Gerwin Ocsena
 

Viewers also liked (20)

Writing DSL's in Scala
Writing DSL's in ScalaWriting DSL's in Scala
Writing DSL's in Scala
Abhijit Sharma
 
Virtualization
VirtualizationVirtualization
Virtualization
turnerwife
 
About Blogs
About BlogsAbout Blogs
About Blogs
guest25061d
 
PO
POPO
PO
cumba2010
 
Downtown Ferndale Business Guide 2011
Downtown Ferndale Business Guide 2011Downtown Ferndale Business Guide 2011
Downtown Ferndale Business Guide 2011
Ferndale Downtown Development Authority
 
Markaların Logo Değişimleri
Markaların Logo  DeğişimleriMarkaların Logo  Değişimleri
Markaların Logo Değişimleri
Yunus Emre
 
Coches Fantasticos
Coches FantasticosCoches Fantasticos
Coches Fantasticos
josevlc
 
NEDMAInno14: The Fundamental Things Still Apply: How to Deal with "Innovation...
NEDMAInno14: The Fundamental Things Still Apply: How to Deal with "Innovation...NEDMAInno14: The Fundamental Things Still Apply: How to Deal with "Innovation...
NEDMAInno14: The Fundamental Things Still Apply: How to Deal with "Innovation...
New England Direct Marketing Association
 
MTech13: "How to Jump Start Sales Productivity with Content" - Paula Crerar
MTech13: "How to Jump Start Sales Productivity with Content" - Paula CrerarMTech13: "How to Jump Start Sales Productivity with Content" - Paula Crerar
MTech13: "How to Jump Start Sales Productivity with Content" - Paula Crerar
New England Direct Marketing Association
 
Yahoo Korea 10th anniversary Plan Concept
Yahoo Korea 10th anniversary Plan ConceptYahoo Korea 10th anniversary Plan Concept
Yahoo Korea 10th anniversary Plan Concept
Jongjin Park
 
Google Places - Global Approach ISS 2012
Google Places - Global Approach ISS 2012Google Places - Global Approach ISS 2012
Google Places - Global Approach ISS 2012
Lisa Myers
 
A Redesign of VisitPhilly.com by Happy Cog
A Redesign of VisitPhilly.com by Happy CogA Redesign of VisitPhilly.com by Happy Cog
A Redesign of VisitPhilly.com by Happy Cog
Kevin Hoffman
 
everdo for ad
everdo for adeverdo for ad
everdo for ad
zopen
 
CEO Roundtable on Local and State Tax Laws
CEO Roundtable on Local and State Tax LawsCEO Roundtable on Local and State Tax Laws
CEO Roundtable on Local and State Tax Laws
Wichita Metro Chamber of Commerce
 
MTech13: "The Power of Marketing Automation in an Inbound World" - Nick Salva...
MTech13: "The Power of Marketing Automation in an Inbound World" - Nick Salva...MTech13: "The Power of Marketing Automation in an Inbound World" - Nick Salva...
MTech13: "The Power of Marketing Automation in an Inbound World" - Nick Salva...
New England Direct Marketing Association
 
Istant report Open Spece Technology "Facciamo il Macello"
Istant report Open Spece Technology "Facciamo il Macello"Istant report Open Spece Technology "Facciamo il Macello"
Istant report Open Spece Technology "Facciamo il Macello"
Conetica
 
Print Technology: Functional Printed Electronics - RFID & NFC versus QR Codes...
Print Technology: Functional Printed Electronics - RFID & NFC versus QR Codes...Print Technology: Functional Printed Electronics - RFID & NFC versus QR Codes...
Print Technology: Functional Printed Electronics - RFID & NFC versus QR Codes...
New England Direct Marketing Association
 
Workflow NPW2010
Workflow NPW2010Workflow NPW2010
Workflow NPW2010
Jonas Brømsø
 
Илья Бирман – Ангстрем
Илья Бирман – АнгстремИлья Бирман – Ангстрем
Илья Бирман – Ангстрем
404fest
 
Writing DSL's in Scala
Writing DSL's in ScalaWriting DSL's in Scala
Writing DSL's in Scala
Abhijit Sharma
 
Virtualization
VirtualizationVirtualization
Virtualization
turnerwife
 
Markaların Logo Değişimleri
Markaların Logo  DeğişimleriMarkaların Logo  Değişimleri
Markaların Logo Değişimleri
Yunus Emre
 
Coches Fantasticos
Coches FantasticosCoches Fantasticos
Coches Fantasticos
josevlc
 
NEDMAInno14: The Fundamental Things Still Apply: How to Deal with "Innovation...
NEDMAInno14: The Fundamental Things Still Apply: How to Deal with "Innovation...NEDMAInno14: The Fundamental Things Still Apply: How to Deal with "Innovation...
NEDMAInno14: The Fundamental Things Still Apply: How to Deal with "Innovation...
New England Direct Marketing Association
 
MTech13: "How to Jump Start Sales Productivity with Content" - Paula Crerar
MTech13: "How to Jump Start Sales Productivity with Content" - Paula CrerarMTech13: "How to Jump Start Sales Productivity with Content" - Paula Crerar
MTech13: "How to Jump Start Sales Productivity with Content" - Paula Crerar
New England Direct Marketing Association
 
Yahoo Korea 10th anniversary Plan Concept
Yahoo Korea 10th anniversary Plan ConceptYahoo Korea 10th anniversary Plan Concept
Yahoo Korea 10th anniversary Plan Concept
Jongjin Park
 
Google Places - Global Approach ISS 2012
Google Places - Global Approach ISS 2012Google Places - Global Approach ISS 2012
Google Places - Global Approach ISS 2012
Lisa Myers
 
A Redesign of VisitPhilly.com by Happy Cog
A Redesign of VisitPhilly.com by Happy CogA Redesign of VisitPhilly.com by Happy Cog
A Redesign of VisitPhilly.com by Happy Cog
Kevin Hoffman
 
everdo for ad
everdo for adeverdo for ad
everdo for ad
zopen
 
MTech13: "The Power of Marketing Automation in an Inbound World" - Nick Salva...
MTech13: "The Power of Marketing Automation in an Inbound World" - Nick Salva...MTech13: "The Power of Marketing Automation in an Inbound World" - Nick Salva...
MTech13: "The Power of Marketing Automation in an Inbound World" - Nick Salva...
New England Direct Marketing Association
 
Istant report Open Spece Technology "Facciamo il Macello"
Istant report Open Spece Technology "Facciamo il Macello"Istant report Open Spece Technology "Facciamo il Macello"
Istant report Open Spece Technology "Facciamo il Macello"
Conetica
 
Print Technology: Functional Printed Electronics - RFID & NFC versus QR Codes...
Print Technology: Functional Printed Electronics - RFID & NFC versus QR Codes...Print Technology: Functional Printed Electronics - RFID & NFC versus QR Codes...
Print Technology: Functional Printed Electronics - RFID & NFC versus QR Codes...
New England Direct Marketing Association
 
Илья Бирман – Ангстрем
Илья Бирман – АнгстремИлья Бирман – Ангстрем
Илья Бирман – Ангстрем
404fest
 
Ad

Similar to Implementing External DSLs Using Scala Parser Combinators (20)

Perl Presentation
Perl PresentationPerl Presentation
Perl Presentation
Sopan Shewale
 
The JavaScript Programming Language
The JavaScript Programming LanguageThe JavaScript Programming Language
The JavaScript Programming Language
Raghavan Mohan
 
Les origines de Javascript
Les origines de JavascriptLes origines de Javascript
Les origines de Javascript
Bernard Loire
 
Javascript by Yahoo
Javascript by YahooJavascript by Yahoo
Javascript by Yahoo
birbal
 
The Java Script Programming Language
The  Java Script  Programming  LanguageThe  Java Script  Programming  Language
The Java Script Programming Language
zone
 
Javascript
JavascriptJavascript
Javascript
guest03a6e6
 
TI1220 Lecture 9: Parsing & interpretation
TI1220 Lecture 9: Parsing & interpretationTI1220 Lecture 9: Parsing & interpretation
TI1220 Lecture 9: Parsing & interpretation
Eelco Visser
 
Javascript
JavascriptJavascript
Javascript
vikram singh
 
Programming
ProgrammingProgramming
Programming
Sean Chia
 
Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009
David Pollak
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
Emil Vladev
 
2 R Tutorial Programming
2 R Tutorial Programming2 R Tutorial Programming
2 R Tutorial Programming
Sakthi Dasans
 
Java Code The traditional way to deal with these in Parsers is the .pdf
Java Code The traditional way to deal with these in Parsers is the .pdfJava Code The traditional way to deal with these in Parsers is the .pdf
Java Code The traditional way to deal with these in Parsers is the .pdf
stopgolook
 
C intro
C introC intro
C intro
Kamran
 
Php-Continuation
Php-ContinuationPhp-Continuation
Php-Continuation
lotlot
 
Oscon 2010 Specs talk
Oscon 2010 Specs talkOscon 2010 Specs talk
Oscon 2010 Specs talk
Eric Torreborre
 
C++ Function
C++ FunctionC++ Function
C++ Function
Hajar
 
Introduction to programming c and data structures
Introduction to programming c and data structuresIntroduction to programming c and data structures
Introduction to programming c and data structures
Pradipta Mishra
 
Python regular expressions
Python regular expressionsPython regular expressions
Python regular expressions
Krishna Nanda
 
Php Reusing Code And Writing Functions
Php Reusing Code And Writing FunctionsPhp Reusing Code And Writing Functions
Php Reusing Code And Writing Functions
mussawir20
 
The JavaScript Programming Language
The JavaScript Programming LanguageThe JavaScript Programming Language
The JavaScript Programming Language
Raghavan Mohan
 
Les origines de Javascript
Les origines de JavascriptLes origines de Javascript
Les origines de Javascript
Bernard Loire
 
Javascript by Yahoo
Javascript by YahooJavascript by Yahoo
Javascript by Yahoo
birbal
 
The Java Script Programming Language
The  Java Script  Programming  LanguageThe  Java Script  Programming  Language
The Java Script Programming Language
zone
 
TI1220 Lecture 9: Parsing & interpretation
TI1220 Lecture 9: Parsing & interpretationTI1220 Lecture 9: Parsing & interpretation
TI1220 Lecture 9: Parsing & interpretation
Eelco Visser
 
Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009
David Pollak
 
2 R Tutorial Programming
2 R Tutorial Programming2 R Tutorial Programming
2 R Tutorial Programming
Sakthi Dasans
 
Java Code The traditional way to deal with these in Parsers is the .pdf
Java Code The traditional way to deal with these in Parsers is the .pdfJava Code The traditional way to deal with these in Parsers is the .pdf
Java Code The traditional way to deal with these in Parsers is the .pdf
stopgolook
 
C intro
C introC intro
C intro
Kamran
 
Php-Continuation
Php-ContinuationPhp-Continuation
Php-Continuation
lotlot
 
C++ Function
C++ FunctionC++ Function
C++ Function
Hajar
 
Introduction to programming c and data structures
Introduction to programming c and data structuresIntroduction to programming c and data structures
Introduction to programming c and data structures
Pradipta Mishra
 
Python regular expressions
Python regular expressionsPython regular expressions
Python regular expressions
Krishna Nanda
 
Php Reusing Code And Writing Functions
Php Reusing Code And Writing FunctionsPhp Reusing Code And Writing Functions
Php Reusing Code And Writing Functions
mussawir20
 
Ad

Recently uploaded (20)

Slack like a pro: strategies for 10x engineering teams
Slack like a pro: strategies for 10x engineering teamsSlack like a pro: strategies for 10x engineering teams
Slack like a pro: strategies for 10x engineering teams
Nacho Cougil
 
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Mike Mingos
 
Design pattern talk by Kaya Weers - 2025 (v2)
Design pattern talk by Kaya Weers - 2025 (v2)Design pattern talk by Kaya Weers - 2025 (v2)
Design pattern talk by Kaya Weers - 2025 (v2)
Kaya Weers
 
AI-proof your career by Olivier Vroom and David WIlliamson
AI-proof your career by Olivier Vroom and David WIlliamsonAI-proof your career by Olivier Vroom and David WIlliamson
AI-proof your career by Olivier Vroom and David WIlliamson
UXPA Boston
 
Could Virtual Threads cast away the usage of Kotlin Coroutines - DevoxxUK2025
Could Virtual Threads cast away the usage of Kotlin Coroutines - DevoxxUK2025Could Virtual Threads cast away the usage of Kotlin Coroutines - DevoxxUK2025
Could Virtual Threads cast away the usage of Kotlin Coroutines - DevoxxUK2025
João Esperancinha
 
Build With AI - In Person Session Slides.pdf
Build With AI - In Person Session Slides.pdfBuild With AI - In Person Session Slides.pdf
Build With AI - In Person Session Slides.pdf
Google Developer Group - Harare
 
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdfKit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Wonjun Hwang
 
Zilliz Cloud Monthly Technical Review: May 2025
Zilliz Cloud Monthly Technical Review: May 2025Zilliz Cloud Monthly Technical Review: May 2025
Zilliz Cloud Monthly Technical Review: May 2025
Zilliz
 
Dark Dynamism: drones, dark factories and deurbanization
Dark Dynamism: drones, dark factories and deurbanizationDark Dynamism: drones, dark factories and deurbanization
Dark Dynamism: drones, dark factories and deurbanization
Jakub Šimek
 
DevOpsDays SLC - Platform Engineers are Product Managers.pptx
DevOpsDays SLC - Platform Engineers are Product Managers.pptxDevOpsDays SLC - Platform Engineers are Product Managers.pptx
DevOpsDays SLC - Platform Engineers are Product Managers.pptx
Justin Reock
 
Q1 2025 Dropbox Earnings and Investor Presentation
Q1 2025 Dropbox Earnings and Investor PresentationQ1 2025 Dropbox Earnings and Investor Presentation
Q1 2025 Dropbox Earnings and Investor Presentation
Dropbox
 
Top-AI-Based-Tools-for-Game-Developers (1).pptx
Top-AI-Based-Tools-for-Game-Developers (1).pptxTop-AI-Based-Tools-for-Game-Developers (1).pptx
Top-AI-Based-Tools-for-Game-Developers (1).pptx
BR Softech
 
Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Kit-Works Team Study_아직도 Dockefile.pdf_김성호Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Wonjun Hwang
 
AsyncAPI v3 : Streamlining Event-Driven API Design
AsyncAPI v3 : Streamlining Event-Driven API DesignAsyncAPI v3 : Streamlining Event-Driven API Design
AsyncAPI v3 : Streamlining Event-Driven API Design
leonid54
 
Mastering Testing in the Modern F&B Landscape
Mastering Testing in the Modern F&B LandscapeMastering Testing in the Modern F&B Landscape
Mastering Testing in the Modern F&B Landscape
marketing943205
 
Agentic Automation - Delhi UiPath Community Meetup
Agentic Automation - Delhi UiPath Community MeetupAgentic Automation - Delhi UiPath Community Meetup
Agentic Automation - Delhi UiPath Community Meetup
Manoj Batra (1600 + Connections)
 
Reimagine How You and Your Team Work with Microsoft 365 Copilot.pptx
Reimagine How You and Your Team Work with Microsoft 365 Copilot.pptxReimagine How You and Your Team Work with Microsoft 365 Copilot.pptx
Reimagine How You and Your Team Work with Microsoft 365 Copilot.pptx
John Moore
 
AI 3-in-1: Agents, RAG, and Local Models - Brent Laster
AI 3-in-1: Agents, RAG, and Local Models - Brent LasterAI 3-in-1: Agents, RAG, and Local Models - Brent Laster
AI 3-in-1: Agents, RAG, and Local Models - Brent Laster
All Things Open
 
RTP Over QUIC: An Interesting Opportunity Or Wasted Time?
RTP Over QUIC: An Interesting Opportunity Or Wasted Time?RTP Over QUIC: An Interesting Opportunity Or Wasted Time?
RTP Over QUIC: An Interesting Opportunity Or Wasted Time?
Lorenzo Miniero
 
Com fer un pla de gestió de dades amb l'eiNa DMP (en anglès)
Com fer un pla de gestió de dades amb l'eiNa DMP (en anglès)Com fer un pla de gestió de dades amb l'eiNa DMP (en anglès)
Com fer un pla de gestió de dades amb l'eiNa DMP (en anglès)
CSUC - Consorci de Serveis Universitaris de Catalunya
 
Slack like a pro: strategies for 10x engineering teams
Slack like a pro: strategies for 10x engineering teamsSlack like a pro: strategies for 10x engineering teams
Slack like a pro: strategies for 10x engineering teams
Nacho Cougil
 
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Optima Cyber - Maritime Cyber Security - MSSP Services - Manolis Sfakianakis ...
Mike Mingos
 
Design pattern talk by Kaya Weers - 2025 (v2)
Design pattern talk by Kaya Weers - 2025 (v2)Design pattern talk by Kaya Weers - 2025 (v2)
Design pattern talk by Kaya Weers - 2025 (v2)
Kaya Weers
 
AI-proof your career by Olivier Vroom and David WIlliamson
AI-proof your career by Olivier Vroom and David WIlliamsonAI-proof your career by Olivier Vroom and David WIlliamson
AI-proof your career by Olivier Vroom and David WIlliamson
UXPA Boston
 
Could Virtual Threads cast away the usage of Kotlin Coroutines - DevoxxUK2025
Could Virtual Threads cast away the usage of Kotlin Coroutines - DevoxxUK2025Could Virtual Threads cast away the usage of Kotlin Coroutines - DevoxxUK2025
Could Virtual Threads cast away the usage of Kotlin Coroutines - DevoxxUK2025
João Esperancinha
 
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdfKit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Kit-Works Team Study_팀스터디_김한솔_nuqs_20250509.pdf
Wonjun Hwang
 
Zilliz Cloud Monthly Technical Review: May 2025
Zilliz Cloud Monthly Technical Review: May 2025Zilliz Cloud Monthly Technical Review: May 2025
Zilliz Cloud Monthly Technical Review: May 2025
Zilliz
 
Dark Dynamism: drones, dark factories and deurbanization
Dark Dynamism: drones, dark factories and deurbanizationDark Dynamism: drones, dark factories and deurbanization
Dark Dynamism: drones, dark factories and deurbanization
Jakub Šimek
 
DevOpsDays SLC - Platform Engineers are Product Managers.pptx
DevOpsDays SLC - Platform Engineers are Product Managers.pptxDevOpsDays SLC - Platform Engineers are Product Managers.pptx
DevOpsDays SLC - Platform Engineers are Product Managers.pptx
Justin Reock
 
Q1 2025 Dropbox Earnings and Investor Presentation
Q1 2025 Dropbox Earnings and Investor PresentationQ1 2025 Dropbox Earnings and Investor Presentation
Q1 2025 Dropbox Earnings and Investor Presentation
Dropbox
 
Top-AI-Based-Tools-for-Game-Developers (1).pptx
Top-AI-Based-Tools-for-Game-Developers (1).pptxTop-AI-Based-Tools-for-Game-Developers (1).pptx
Top-AI-Based-Tools-for-Game-Developers (1).pptx
BR Softech
 
Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Kit-Works Team Study_아직도 Dockefile.pdf_김성호Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Kit-Works Team Study_아직도 Dockefile.pdf_김성호
Wonjun Hwang
 
AsyncAPI v3 : Streamlining Event-Driven API Design
AsyncAPI v3 : Streamlining Event-Driven API DesignAsyncAPI v3 : Streamlining Event-Driven API Design
AsyncAPI v3 : Streamlining Event-Driven API Design
leonid54
 
Mastering Testing in the Modern F&B Landscape
Mastering Testing in the Modern F&B LandscapeMastering Testing in the Modern F&B Landscape
Mastering Testing in the Modern F&B Landscape
marketing943205
 
Reimagine How You and Your Team Work with Microsoft 365 Copilot.pptx
Reimagine How You and Your Team Work with Microsoft 365 Copilot.pptxReimagine How You and Your Team Work with Microsoft 365 Copilot.pptx
Reimagine How You and Your Team Work with Microsoft 365 Copilot.pptx
John Moore
 
AI 3-in-1: Agents, RAG, and Local Models - Brent Laster
AI 3-in-1: Agents, RAG, and Local Models - Brent LasterAI 3-in-1: Agents, RAG, and Local Models - Brent Laster
AI 3-in-1: Agents, RAG, and Local Models - Brent Laster
All Things Open
 
RTP Over QUIC: An Interesting Opportunity Or Wasted Time?
RTP Over QUIC: An Interesting Opportunity Or Wasted Time?RTP Over QUIC: An Interesting Opportunity Or Wasted Time?
RTP Over QUIC: An Interesting Opportunity Or Wasted Time?
Lorenzo Miniero
 

Implementing External DSLs Using Scala Parser Combinators

  • 1. Implementing External DSLs Using Scala Parser Combinators St. Louis Lambda Lounge Sept. 3, 2009 Tim Dalton Senior Software Engineer Object Computing Inc.
  • 2. External vs Internal DSL Internal DSLs are implemented using syntax of “host” programming language Examples Fluent APIs in Java RSpec and ScalaSpec Constrained by features of programming language External DSLs syntax is only limited by capabilities of the parser
  • 3. What is a Combinator ? Combinators are functions that can be combined to perform more complex operations Concept originates in Lambda Calculus Mostly comes from the Haskell community Haskell implementations use Monads Scala implementation “almost Monadic”
  • 4. Scala’s Parser Implementation Context-free LL grammar Left to right Leftmost derivation Recursive descent Backtracking There are ways to prevent backtracking Advances planned for Scala 2.8 Support for Packrat parsing Parser Expression Grammar More predictive with less recursion and backtracking
  • 5. Scala Combinator Parser Hierarchy scala.util.parsing.combinator.Parsers scala.util.parsing.combinator.syntactical.TokenParsers scala.util.parsing.combinator.syntactical.StdTokenParsers scala.util.parsing.combinator.RegexParsers scala.util.parsing.combinator.JavaTokenParsers
  • 6. A Simple Logo(-Like) Interpreter Only a few commands: Right Turn <angle-degrees> Left Turn <angle-degrees> Forward <number-of-pixels> Repeat <nested sequence of other commands>
  • 7. Grammar for Simple Logo forward = (“FORWARD” | “FD”) positive-integer right = (“RIGHT” | “RT) positive-integer left = (“LEFT” | “LT”) positive-integer repeat = “REPEAT” positive-integer “[“{statement}”]” statement = right | left | forward | repeat program = { statement }
  • 8. Scala Code to Implement Parser object LogoParser extends RegexParsers { def positiveInteger = &quot;&quot;&quot;\d+&quot;&quot;&quot;r def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~positiveInteger def right = (&quot;RT&quot;|&quot;RIGHT&quot;)~positiveInteger def left = (&quot;LT&quot;|&quot;LEFT&quot;)~positiveInteger def repeat = &quot;REPEAT&quot; ~ positiveInteger ~ &quot;[&quot; ~ rep(statement) ~ &quot;]&quot; def statement:Parser[Any] = forward | right | left | repeat def program = rep(statement) }
  • 9. Scala Code to Implement Parser An internal DSL is used to implement an External One Methods on preceding slide are referred to as parser generators RegexParsers is subclass of Parsers trait that provides a generic parser combinator
  • 10. A Closer Look def positiveInteger = &quot;&quot;&quot;\d+&quot;&quot;&quot;r The trailing “r” is a method call the converts the string to a Regex object More verbose syntax: &quot;&quot;&quot;\d+&quot;&quot;&quot;.r() String does not have an r() method !! Class RichString does, so an implicit conversion is done
  • 11. Implicit Conversions One of the more powerful / dangerous features of Scala is implicit conversions RichString.r method signature def r : Regex scala.Predef implicit convertor implicit def stringWrapper( x : java.lang.String) : RichString The Scala compiler will look for implicit convertors in scope and insert them implicitly “ With great power, comes great responsibility”
  • 12. Back to the Parser def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~positiveInteger The “|” and “~” are methods of class Parsers.Parser[T] !! RegexParser has implicit conversions: implicit def literal(s : String) : Parser[String] implicit def regex(r : Regex) : Parser[String] Parser generator methods should return something that can be at least be converted to Parser[T]
  • 13. Parser[T]’s and ParseResult[T]’s Parsers.Parser[T] Extends Reader => ParseResult[T] This makes it a function object ParserResult[T] Hierarchy: Parsers.Success Parsers.NoSuccess Parsers.Failure Parsers.Error Invoking Parsers[T] function object return one of the above subclasses
  • 14. Combining Parser[T]’s Signature for Parser[T].| method: def |[U >: T](q : => Parser[U]) : Parser[U] Parser Combinator for alternative composition (OR) Succeeds (returns Parsers.Success) if either “this” Parser[T] succeeds or “q” Parser[U] succeeds Type U must be same or super-class of type T.
  • 15. Combining Parser[T]’s Signature of Parser[T].~ method: def ~[U](p : => Parser[U]) : Parser[~[T, U]] Parser Combinator for sequential composition Succeeds only if “this” Parser succeeds and “q” Parser succeeds Return an instance “~” that contain both results Yes, “~” is also a class ! Like a Pair, but easier to pattern match on
  • 16. Forward March Back to the specification of forward: def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~positiveInteger For this combinator to succeed, Either the Parser for literal “FD” or “FORWARD” And the Parser for the positiveInt Regex Both the literal strings and Regex result of positiveInt are implicitly converted to Parser[String]
  • 17. Repetition Next lines of note: def repeat = &quot;REPEAT&quot; ~ positiveInteger ~ &quot;[&quot; ~ rep(statement) ~ &quot;]&quot; def statement:Parser[Any] = forward | right | left | repeat Type for either repeat or statement need to be explicitly specified due to recursion The rep method specifies that Parser can be repeated
  • 18. Repetition Signature for Parsers.rep method: def rep[T](p : => Parser[T]) : Parser[List[T]] Parser Combinator for repetitions Parses input until Parser, p, fails. Returns consecutive successful results as List.
  • 19. Other Forms of Repetition def repsep[T](p: => Parser[T], q: => Parser[Any]) : Parser[List[T]] Specifies a Parser to be interleaved in the repetition Example: repsep(term, &quot;,&quot;) def rep1[T](p: => Parser[T]): Parser[List[T]] Parses non-empty repetitions def repN[T](n : Int, p : => Parser[T]) : Parser[List[T]] Parses a specified number of repetitions
  • 20. Execution Root Parser Generator: def program = rep(statement) To Execute the Parser parseAll(program, &quot;REPEAT 4 [FD 100 RT 90]&quot;) Returns Parsers.Success[List[Parsers.~[…]]] Remember ,Parsers.Success[T] is subclass of ParseResult[T] toString: [1.24] parsed: List(((((REPEAT~4)~[)~List((FD~100), (RT~90)))~])) The “…” indicates many levels nested Parsers
  • 21. Not-so-Happy Path Example of failed Parsing: parseAll(program, &quot;REPEAT 4 [FD 100 RT 90 ) &quot;) Returns Parsers.Failure Subclass of ParseResult[Nothing] toString: [1.23] failure: `]' expected but `)' found REPEAT 4 [FD 100 RT 90) ^ Failure message not always so “precise”
  • 22. Making Something Useful Successful parse results need to transformed into something that can be evaluated Enter the “eye brows” method of Parser[T]: def ^^[U](f : (T) => U) : Parser[U] Parser combinator for function application
  • 23. Eye Brows Example Example of “^^” method: def positiveInteger = &quot;&quot;&quot;\d+&quot;&quot;&quot;.r ^^ { x:String => x.toInt } Now positiveInteger generates Parser[Int] instead of Parser[String] Transformer can be shortened to “{ _.toInt }”
  • 24. Implementing Commands For the statements we need a hierarchy of command classes: sealed abstract class LogoCommand case class Forward(x: Int) extends LogoCommand case class Turn(x: Int) extends LogoCommand case class Repeat(i: Int, e: List[LogoCommand]) extends LogoCommand
  • 25. Transforming into Commands The Forward command: def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~positiveInteger ^^ { case _~value => Forward(value) } A ~[String, Int] is being passed in the transformer Pattern matching is to extract the Int, value and construct a Forward instance Forward is a case class, so “new” not needed Case constructs can be partial functions themselves. Longer form: … ^^ { tilde => tilde match { case _~value => Forward(value) }}
  • 26. Derivates of “~” Two methods related to “~”: def <~ [U](p: => Parser[U]): Parser[T] Parser combinator for sequential composition which keeps only the left result def ~> [U](p: => Parser[U]): Parser[U] Parser combinator for sequential composition which keeps only the right result Note, neither returns a “~” instance The forward method can be simplified: def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~>positiveInteger ^^ { Forward(_) }
  • 27. Updated Parser def positiveInteger = &quot;&quot;&quot;\d+&quot;&quot;&quot;.r ^^ { _.toInt } def forward = (&quot;FD&quot;|&quot;FORWARD&quot;)~>positiveInteger ^^ { Forward(_) } def right = (&quot;RT&quot;|&quot;RIGHT&quot;)~>positiveInteger ^^ { x => Turn(-x) } def left = (&quot;LT&quot;|&quot;LEFT&quot;)~>positiveInteger ^^ { Turn(_) } def repeat = &quot;REPEAT&quot; ~> positiveInteger ~ &quot;[&quot; ~ rep(statement) <~ &quot;]&quot; ^^ { case number~_~statements => Repeat(number, statements)}
  • 28. Updated Parser Results Executing the Parser now: parseAll(program, &quot;REPEAT 4 [FD 100 RT 90]&quot;) Results: [1.24] parsed: List(Repeat(4,List(Forward(100), Turn(-90)))) Returns Parsers.Success[List[Repeat]] This can be evaluated !!
  • 29. Evaluation class LogoEvaluationState { var x = 0 var y = 0 var heading = 0 } implicit def dblToInt(d: Double):Int = if (d > 0) (d+0.5).toInt else (d-0.5).toInt def parse(s: String) : List[LogoCommand] = LogoParser.parse(s).get def evaluate(parseResult: LogoParser.ParseResult[List[LogoCommand]], g:Graphics2D) { var state = new LogoEvaluationState if (parseResult.successful) { evaluate(parseResult.get, g, state) } // draw turtle evaluate(parse(&quot;RT 90 FD 3 LT 110 FD 10 LT 140 FD 10 LT 110 FD 3&quot;), g, state) } // Continued...
  • 30. Evaluation (More Functional) private def evaluate(list: List[LogoCommand], g:Graphics2D, state:LogoEvaluationState) { if (!list.isEmpty) { val head :: tail = list head match { case Forward(distance) => { val (nextX, nextY) = (state.x + distance * sin(toRadians(state.heading)), state.y + distance * cos(toRadians(state.heading))) g.drawLine(state.x, state.y, nextX, nextY) state.x = nextX state.y = nextY evaluate(tail, g, state) } case Turn(degrees) => { state.heading += degrees evaluate(tail, g, state) } case Repeat(0, _) => evaluate(tail, g, state) case Repeat(count, statements) => evaluate(statements ::: Repeat(count-1, statements)::tail, g, state) } } }
  • 31. Evaluation (More Imperative) def evaluate(list: List[LogoCommand], g:Graphics2D, state:LogoEvaluationState) { list.foreach(evaluate(_, g, state)) } def evaluate(command:LogoCommand, g:Graphics2D, state:LogoEvaluationState) { command match { case Forward(distance) => { val (nextX, nextY) = (state.x + distance * Math.sin(Math.toRadians(state.heading)), state.y + distance * Math.cos(Math.toRadians(state.heading))) g.drawLine(state.x, state.y, nextX, nextY) state.x = nextX state.y = nextY } case Turn(degrees) => state.heading += degrees case Repeat(count, statements) => (0 to count).foreach { _ => evaluate(statements, g, state) } } }

Editor's Notes

  • #8: (|) = OR logic { } = repetition
  • #11: The multiline string notation is used so escaping “\\” in the regex is not needed
  • #12: Internal DSLs in Scala leverage implicit conversion to a great degree to allow a more flexible “syntax”
  • #16: ~ is a case class.
  • #18: Because statement and repeat invoke each other and therefore can be invoked recursively, The return type for one must be specified
  • #20: There is also rep1sep
  • #22: Demonstrate no so precise message “RT” -&gt; “ET”
  • #28: For some reason Scala compile didn’t like { Turn(-_) }
  • #31: Tail Recursive !!
  翻译: