Merge pull request #1 from aaronlevin/compile-readme
Fix README so it compiles + More Complete Example
G. D. Ritter
9 years ago
| 454 | 454 | literals: |
| 455 | 455 | |
| 456 | 456 | ~~~~.haskell |
| 457 | {-# LANGUAGE OverloadedStrings #-} | |
| 458 | ||
| 459 | module SCargotExample where | |
| 460 | ||
| 461 | import Control.Applicative ((<|>)) | |
| 462 | import Data.Char (isDigit) | |
| 463 | import Data.SCargot | |
| 464 | import Data.SCargot.Repr.Basic | |
| 465 | import Data.Text (Text, pack) | |
| 466 | import Numeric (readHex) | |
| 467 | import Text.Parsec (anyChar, char, digit, many1, manyTill, newline, satisfy, string) | |
| 468 | import Text.Parsec.Text (Parser) | |
| 469 | ||
| 457 | 470 | -- Our operators are going to represent addition, subtraction, or |
| 458 | 471 | -- multiplication |
| 459 | 472 | data Op = Add | Sub | Mul deriving (Eq, Show) |
| 468 | 481 | |
| 469 | 482 | -- Conversions to and from our Expr type |
| 470 | 483 | toExpr :: SExpr Atom -> Either String Expr |
| 471 |
toExpr (A (AOp op) ::: l ::: r ::: Nil) = EOp op <$> |
|
| 484 | toExpr (A (AOp op) ::: l ::: r ::: Nil) = EOp op <$> toExpr l <*> toExpr r | |
| 472 | 485 | toExpr (A (ANum n)) = pure (ENum n) |
| 473 | 486 | toExpr sexpr = Left ("Unable to parse expression: " ++ show sexpr) |
| 474 | 487 | |
| 475 | 488 | fromExpr :: Expr -> SExpr Atom |
| 476 | 489 | fromExpr (EOp op l r) = A (AOp op) ::: fromExpr l ::: fromExpr r ::: Nil |
| 477 |
fromExpr (ENum n) = A |
|
| 490 | fromExpr (ENum n) = A (ANum n) ::: Nil | |
| 478 | 491 | |
| 479 | 492 | -- Parser and serializer for our Atom type |
| 480 | 493 | pAtom :: Parser Atom |
| 481 | pAtom = ((ANum . read . T.unpack) <$> many1 isDigit) | |
| 482 | <|> (char "+" *> pure (AOp Add)) | |
| 483 | <|> (char "-" *> pure (AOp Sub)) | |
| 484 | <|> (char "*" *> pure (AOp Mul)) | |
| 494 | pAtom = ((ANum . read) <$> many1 digit) | |
| 495 | <|> (char '+' *> pure (AOp Add)) | |
| 496 | <|> (char '-' *> pure (AOp Sub)) | |
| 497 | <|> (char '*' *> pure (AOp Mul)) | |
| 485 | 498 | |
| 486 | 499 | sAtom :: Atom -> Text |
| 487 | 500 | sAtom (AOp Add) = "+" |
| 488 | 501 | sAtom (AOp Sub) = "-" |
| 489 | 502 | sAtom (AOp Mul) = "*" |
| 490 |
sAtom (ANum n) = |
|
| 503 | sAtom (ANum n) = pack (show n) | |
| 491 | 504 | |
| 492 | 505 | -- Our comment syntax is going to be Haskell-like: |
| 493 | 506 | hsComment :: Parser () |
| 494 |
hsComment = string "--" >> manyTill |
|
| 507 | hsComment = string "--" >> manyTill anyChar newline >> return () | |
| 495 | 508 | |
| 496 | 509 | -- Our custom reader macro: grab the parse stream and read a |
| 497 | 510 | -- hexadecimal number from it: |
| 498 | 511 | hexReader :: Reader Atom |
| 499 | hexReader _ = (Num . readHex . T.unpack) <$> takeWhile1 isHexDigit | |
| 500 | where isHexDigit c = isDigit c || c `elem` "AaBbCcDdEeFf" | |
| 501 | rd = readHex . head . fst | |
| 512 | hexReader _ = (A . ANum . rd) <$> many1 (satisfy isHexDigit) | |
| 513 | where isHexDigit c = isDigit c || c `elem` hexChars | |
| 514 | rd = fst . head . readHex | |
| 515 | hexChars :: String | |
| 516 | hexChars = "AaBbCcDdEeFf" | |
| 502 | 517 | |
| 503 | 518 | -- Our final s-expression parser and printer: |
| 504 | 519 | myLangParser :: SExprParser Atom Expr |
| 508 | 523 | $ setCarrier toExpr -- convert final repr to Expr |
| 509 | 524 | $ mkParser pAtom -- create spec with Atom type |
| 510 | 525 | |
| 511 |
mkLangPrinter :: S |
|
| 526 | mkLangPrinter :: SExprPrinter Atom Expr | |
| 512 | 527 | mkLangPrinter |
| 513 | 528 | = setFromCarrier fromExpr |
| 514 | 529 | $ setIndentStrategy (const Align) |
| 515 | 530 | $ basicPrint sAtom |
| 531 | ||
| 516 | 532 | ~~~~ |
| 517 | 533 | |
| 518 | 534 | Keep in mind that you often won't need to write all this by hand, |