Merge pull request #1 from aaronlevin/compile-readme
Fix README so it compiles + More Complete Example
G. D. Ritter
8 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, |