finish v1
This commit is contained in:
parent
3387bb886c
commit
cf91f09d68
4 changed files with 323 additions and 6 deletions
109
parsec.html
109
parsec.html
|
@ -308,9 +308,112 @@ expecting digit or <span class="dt">Number</span> between <span class="dv">0</sp
|
||||||
<pre class="sourceCode haskell"><code class="sourceCode haskell">lexeme parser <span class="fu">=</span> whitespaces <span class="fu">*></span> parser <span class="fu"><*</span> whitespaces</code></pre>
|
<pre class="sourceCode haskell"><code class="sourceCode haskell">lexeme parser <span class="fu">=</span> whitespaces <span class="fu">*></span> parser <span class="fu"><*</span> whitespaces</code></pre>
|
||||||
</section>
|
</section>
|
||||||
<section class="slide">
|
<section class="slide">
|
||||||
<h2 id="data-structure">Data Structure</h2>
|
<h2 id="scheme">Scheme</h2>
|
||||||
<p>Remember from text to data structure</p>
|
<p><a href="https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours">Write Yourself a Scheme in 48 hours</a></p>
|
||||||
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Tree</span> <span class="fu">=</span> <span class="dt">Node</span> <span class="dt">Element</span> [<span class="dt">Tree</span>]</code></pre>
|
<p>Remember from text to data structure. Our data structure:</p>
|
||||||
|
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">LispVal</span> <span class="fu">=</span> <span class="dt">Atom</span> <span class="dt">String</span>
|
||||||
|
<span class="fu">|</span> <span class="dt">List</span> [<span class="dt">LispVal</span>]
|
||||||
|
<span class="fu">|</span> <span class="dt">DottedList</span> [<span class="dt">LispVal</span>] <span class="dt">LispVal</span>
|
||||||
|
<span class="fu">|</span> <span class="dt">Number</span> <span class="dt">Integer</span>
|
||||||
|
<span class="fu">|</span> <span class="dt">String</span> <span class="dt">String</span>
|
||||||
|
<span class="fu">|</span> <span class="dt">Bool</span> <span class="dt">Bool</span></code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="parse-string">Parse String</h2>
|
||||||
|
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseString ::</span> <span class="dt">Parser</span> <span class="dt">LispVal</span>
|
||||||
|
parseString <span class="fu">=</span> <span class="kw">do</span>
|
||||||
|
char <span class="ch">'"'</span>
|
||||||
|
x <span class="ot"><-</span> many (noneOf <span class="st">"\""</span>)
|
||||||
|
char <span class="ch">'"'</span>
|
||||||
|
return (<span class="dt">String</span> x)</code></pre>
|
||||||
|
<pre><code>-- parseString on '"toto"'
|
||||||
|
(String "toto") :: LispVal
|
||||||
|
-- parseString on '" hello"'
|
||||||
|
(String " hello") :: LispVal</code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="parse-atom">Parse Atom</h2>
|
||||||
|
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">symbol ::</span> <span class="dt">Parser</span> <span class="dt">Char</span>
|
||||||
|
symbol <span class="fu">=</span> oneOf <span class="st">"!#$%<span class="and">&</span>|*+-/:<=>?@^_~"</span>
|
||||||
|
|
||||||
|
<span class="ot">parseAtom ::</span> <span class="dt">Parser</span> <span class="dt">LispVal</span>
|
||||||
|
parseAtom <span class="fu">=</span> <span class="kw">do</span>
|
||||||
|
first <span class="ot"><-</span> letter <span class="fu"><|></span> symbol
|
||||||
|
rest <span class="ot"><-</span> many (letter <span class="fu"><|></span> digit <span class="fu"><|></span> symbol)
|
||||||
|
<span class="kw">let</span> atom <span class="fu">=</span> first<span class="fu">:</span>rest
|
||||||
|
return <span class="fu">$</span> <span class="kw">case</span> atom <span class="kw">of</span>
|
||||||
|
<span class="st">"#t"</span> <span class="ot">-></span> <span class="dt">Bool</span> <span class="dt">True</span>
|
||||||
|
<span class="st">"#f"</span> <span class="ot">-></span> <span class="dt">Bool</span> <span class="dt">False</span>
|
||||||
|
_ <span class="ot">-></span> <span class="dt">Atom</span> atom</code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="test-parseatom">Test <code>parseAtom</code></h2>
|
||||||
|
<pre><code>-- parseAtom on '#t'
|
||||||
|
(Bool True) :: LispVal
|
||||||
|
-- parseAtom on '#f'
|
||||||
|
(Bool False) :: LispVal
|
||||||
|
-- parseAtom on 'some-atom'
|
||||||
|
(Atom "some-atom") :: LispVal</code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="parse-number">Parse Number</h2>
|
||||||
|
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseNumber ::</span> <span class="dt">Parser</span> <span class="dt">LispVal</span>
|
||||||
|
parseNumber <span class="fu">=</span> <span class="dt">Number</span> <span class="fu">.</span> read <span class="fu"><$></span> many1 digit</code></pre>
|
||||||
|
<pre><code>-- parseNumber on '18'
|
||||||
|
Number 18 :: LispVal
|
||||||
|
-- parseNumber on '188930992344321234'
|
||||||
|
Number 188930992344321234 :: LispVal</code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="compose-all-parsers">Compose all parsers</h2>
|
||||||
|
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseExpr ::</span> <span class="dt">Parser</span> <span class="dt">LispVal</span>
|
||||||
|
parseExpr <span class="fu">=</span> parseAtom
|
||||||
|
<span class="fu"><||></span> parseString
|
||||||
|
<span class="fu"><||></span> parseNumber</code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="test-the-parser">Test the parser</h2>
|
||||||
|
<pre><code>-- parseExpr on '188930992344321234'
|
||||||
|
Number 188930992344321234 :: LispVal
|
||||||
|
-- parseExpr on '#t'
|
||||||
|
Bool True :: LispVal
|
||||||
|
-- parseExpr on 'just-some-word'
|
||||||
|
Atom "just-some-word" :: LispVal
|
||||||
|
-- parseExpr on '%-symbol-start'
|
||||||
|
Atom "%-symbol-start" :: LispVal
|
||||||
|
-- parseExpr on '"a String"'
|
||||||
|
String "a String" :: LispVal</code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="recursive-parsers">Recursive Parsers</h2>
|
||||||
|
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseList ::</span> <span class="dt">Parser</span> <span class="dt">LispVal</span>
|
||||||
|
parseList <span class="fu">=</span> <span class="dt">List</span> <span class="fu"><$></span>
|
||||||
|
(char <span class="ch">'('</span> <span class="fu">*></span> sepBy parseExpr' spaces <span class="fu"><*</span> char <span class="ch">')'</span> )
|
||||||
|
|
||||||
|
<span class="ot">parseExpr' ::</span> <span class="dt">Parser</span> <span class="dt">LispVal</span>
|
||||||
|
parseExpr' <span class="fu">=</span> parseAtom
|
||||||
|
<span class="fu"><||></span> parseString
|
||||||
|
<span class="fu"><||></span> parseNumber
|
||||||
|
<span class="fu"><||></span> parseList</code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="test-parse-list">Test Parse List</h2>
|
||||||
|
<pre><code>-- parseExpr' on '(foo (bar baz))'
|
||||||
|
List [Atom "foo",List [Atom "bar",Atom "baz"]] :: LispVal
|
||||||
|
|
||||||
|
-- parseExpr' on '(foo (bar)'
|
||||||
|
"parseExpr'" (line 1, column 11):
|
||||||
|
unexpected end of input
|
||||||
|
expecting white space, letter, "\"", digit, "(" or ")"
|
||||||
|
|
||||||
|
-- parseExpr' on '(((foo)) bar)'
|
||||||
|
List [List [List [Atom "foo"]],Atom "bar"] :: LispVal</code></pre>
|
||||||
|
</section>
|
||||||
|
<section class="slide">
|
||||||
|
<h2 id="conclusion">Conclusion</h2>
|
||||||
|
<p>So Parser are more powerful than regular expression.<br />Parsec make it very easy to use.<br />Easy to read and to manipulate.</p>
|
||||||
|
<p>Notice how you could use parser as any other object in Haskell. You could <code>mapM</code> them for example.</p>
|
||||||
|
<p>Any question?</p>
|
||||||
</section>
|
</section>
|
||||||
<!-- End slides. -->
|
<!-- End slides. -->
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -25,10 +25,141 @@ Let's write a minimal DSL
|
||||||
lexeme parser = whitespaces *> parser <* whitespaces
|
lexeme parser = whitespaces *> parser <* whitespaces
|
||||||
```
|
```
|
||||||
|
|
||||||
## Data Structure
|
## Scheme
|
||||||
|
|
||||||
Remember from text to data structure
|
[Write Yourself a Scheme in 48 hours](https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours)
|
||||||
|
|
||||||
|
Remember from text to data structure. Our data structure:
|
||||||
|
|
||||||
``` haskell
|
``` haskell
|
||||||
data Tree = Node Element [Tree]
|
data LispVal = Atom String
|
||||||
|
| List [LispVal]
|
||||||
|
| DottedList [LispVal] LispVal
|
||||||
|
| Number Integer
|
||||||
|
| String String
|
||||||
|
| Bool Bool
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Parse String
|
||||||
|
|
||||||
|
``` haskell
|
||||||
|
parseString :: Parser LispVal
|
||||||
|
parseString = do
|
||||||
|
char '"'
|
||||||
|
x <- many (noneOf "\"")
|
||||||
|
char '"'
|
||||||
|
return (String x)
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
-- parseString on '"toto"'
|
||||||
|
(String "toto") :: LispVal
|
||||||
|
-- parseString on '" hello"'
|
||||||
|
(String " hello") :: LispVal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parse Atom
|
||||||
|
|
||||||
|
``` haskell
|
||||||
|
symbol :: Parser Char
|
||||||
|
symbol = oneOf "!#$%&|*+-/:<=>?@^_~"
|
||||||
|
|
||||||
|
parseAtom :: Parser LispVal
|
||||||
|
parseAtom = do
|
||||||
|
first <- letter <|> symbol
|
||||||
|
rest <- many (letter <|> digit <|> symbol)
|
||||||
|
let atom = first:rest
|
||||||
|
return $ case atom of
|
||||||
|
"#t" -> Bool True
|
||||||
|
"#f" -> Bool False
|
||||||
|
_ -> Atom atom
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test `parseAtom`
|
||||||
|
|
||||||
|
```
|
||||||
|
-- parseAtom on '#t'
|
||||||
|
(Bool True) :: LispVal
|
||||||
|
-- parseAtom on '#f'
|
||||||
|
(Bool False) :: LispVal
|
||||||
|
-- parseAtom on 'some-atom'
|
||||||
|
(Atom "some-atom") :: LispVal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parse Number
|
||||||
|
|
||||||
|
``` haskell
|
||||||
|
parseNumber :: Parser LispVal
|
||||||
|
parseNumber = Number . read <$> many1 digit
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
-- parseNumber on '18'
|
||||||
|
Number 18 :: LispVal
|
||||||
|
-- parseNumber on '188930992344321234'
|
||||||
|
Number 188930992344321234 :: LispVal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compose all parsers
|
||||||
|
|
||||||
|
``` haskell
|
||||||
|
parseExpr :: Parser LispVal
|
||||||
|
parseExpr = parseAtom
|
||||||
|
<||> parseString
|
||||||
|
<||> parseNumber
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test the parser
|
||||||
|
|
||||||
|
````
|
||||||
|
-- parseExpr on '188930992344321234'
|
||||||
|
Number 188930992344321234 :: LispVal
|
||||||
|
-- parseExpr on '#t'
|
||||||
|
Bool True :: LispVal
|
||||||
|
-- parseExpr on 'just-some-word'
|
||||||
|
Atom "just-some-word" :: LispVal
|
||||||
|
-- parseExpr on '%-symbol-start'
|
||||||
|
Atom "%-symbol-start" :: LispVal
|
||||||
|
-- parseExpr on '"a String"'
|
||||||
|
String "a String" :: LispVal
|
||||||
|
````
|
||||||
|
|
||||||
|
## Recursive Parsers
|
||||||
|
|
||||||
|
``` haskell
|
||||||
|
parseList :: Parser LispVal
|
||||||
|
parseList = List <$>
|
||||||
|
(char '(' *> sepBy parseExpr' spaces <* char ')' )
|
||||||
|
|
||||||
|
parseExpr' :: Parser LispVal
|
||||||
|
parseExpr' = parseAtom
|
||||||
|
<||> parseString
|
||||||
|
<||> parseNumber
|
||||||
|
<||> parseList
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Parse List
|
||||||
|
|
||||||
|
```
|
||||||
|
-- parseExpr' on '(foo (bar baz))'
|
||||||
|
List [Atom "foo",List [Atom "bar",Atom "baz"]] :: LispVal
|
||||||
|
|
||||||
|
-- parseExpr' on '(foo (bar)'
|
||||||
|
"parseExpr'" (line 1, column 11):
|
||||||
|
unexpected end of input
|
||||||
|
expecting white space, letter, "\"", digit, "(" or ")"
|
||||||
|
|
||||||
|
-- parseExpr' on '(((foo)) bar)'
|
||||||
|
List [List [List [Atom "foo"]],Atom "bar"] :: LispVal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
So Parser are more powerful than regular expression.
|
||||||
|
Parsec make it very easy to use.
|
||||||
|
Easy to read and to manipulate.
|
||||||
|
|
||||||
|
Notice how you could use parser as any other object in Haskell.
|
||||||
|
You could `mapM` them for example.
|
||||||
|
|
||||||
|
Any question?
|
||||||
|
|
83
parsec/examples/scheme.hs
Normal file
83
parsec/examples/scheme.hs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
{-# LANGUAGE DeriveDataTypeable #-}
|
||||||
|
import Control.Applicative hiding (many, (<|>))
|
||||||
|
import Text.Parsec
|
||||||
|
import Data.Typeable
|
||||||
|
import Control.Monad (guard)
|
||||||
|
|
||||||
|
type Parser a = Parsec String () a
|
||||||
|
|
||||||
|
data LispVal = Atom String
|
||||||
|
| List [LispVal]
|
||||||
|
| DottedList [LispVal] LispVal
|
||||||
|
| Number Integer
|
||||||
|
| String String
|
||||||
|
| Bool Bool
|
||||||
|
deriving (Show, Typeable)
|
||||||
|
|
||||||
|
parseString :: Parser LispVal
|
||||||
|
parseString = do
|
||||||
|
char '"'
|
||||||
|
x <- many (noneOf "\"")
|
||||||
|
char '"'
|
||||||
|
return (String x)
|
||||||
|
|
||||||
|
symbol :: Parser Char
|
||||||
|
symbol = oneOf "!#$%&|*+-/:<=>?@^_~"
|
||||||
|
|
||||||
|
parseAtom :: Parser LispVal
|
||||||
|
parseAtom = do
|
||||||
|
first <- letter <|> symbol
|
||||||
|
rest <- many (letter <|> digit <|> symbol)
|
||||||
|
let atom = first:rest
|
||||||
|
return $ case atom of
|
||||||
|
"#t" -> Bool True
|
||||||
|
"#f" -> Bool False
|
||||||
|
_ -> Atom atom
|
||||||
|
|
||||||
|
parseNumber :: Parser LispVal
|
||||||
|
parseNumber = Number . read <$> many1 digit
|
||||||
|
|
||||||
|
parseExpr :: Parser LispVal
|
||||||
|
parseExpr = parseAtom
|
||||||
|
<||> parseString
|
||||||
|
<||> parseNumber
|
||||||
|
|
||||||
|
(<||>) parser1 parser2 = try parser1 <|> parser2
|
||||||
|
|
||||||
|
|
||||||
|
parseList :: Parser LispVal
|
||||||
|
parseList = List <$>
|
||||||
|
(char '(' *> sepBy parseExpr' spaces <* char ')' )
|
||||||
|
|
||||||
|
parseExpr' :: Parser LispVal
|
||||||
|
parseExpr' = parseAtom
|
||||||
|
<||> parseString
|
||||||
|
<||> parseNumber
|
||||||
|
<||> parseList
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
-- test parseString "parseString" "\"toto\""
|
||||||
|
-- test parseString "parseString" "\" hello\""
|
||||||
|
-- test parseAtom "parseAtom" "#t"
|
||||||
|
-- test parseAtom "parseAtom" "#f"
|
||||||
|
-- test parseAtom "parseAtom" "some-atom"
|
||||||
|
-- test parseNumber "parseNumber" "18"
|
||||||
|
-- test parseNumber "parseNumber" "188930992344321234"
|
||||||
|
-- test parseExpr "parseExpr" "188930992344321234"
|
||||||
|
-- test parseExpr "parseExpr" "#t"
|
||||||
|
-- test parseExpr "parseExpr" "just-some-word"
|
||||||
|
-- test parseExpr "parseExpr" "%-symbol-start"
|
||||||
|
-- test parseExpr "parseExpr" "\"a String\""
|
||||||
|
test parseExpr' "parseExpr'" "(foo (bar baz))"
|
||||||
|
test parseExpr' "parseExpr'" "(foo (bar)"
|
||||||
|
test parseExpr' "parseExpr'" "(((foo)) bar)"
|
||||||
|
|
||||||
|
test :: (Typeable a, Show a) => Parser a -> String -> String -> IO ()
|
||||||
|
test parser description string = do
|
||||||
|
putStrLn $ "-- " ++ description ++ " on '" ++ string ++ "'"
|
||||||
|
let res = parse parser description string
|
||||||
|
case res of
|
||||||
|
Left err -> print err
|
||||||
|
Right value -> putStr $ show value ++ " :: " ++ show (typeOf value)
|
||||||
|
putStrLn ""
|
||||||
|
|
Loading…
Reference in a new issue