Browse Source

Create executable example

aaron levin 8 years ago
parent
commit
c6c867501b
3 changed files with 101 additions and 0 deletions
  1. 2 0
      README.md
  2. 88 0
      example/example.hs
  3. 11 0
      s-cargot.cabal

+ 2 - 0
README.md

@@ -529,6 +529,8 @@ mkLangPrinter
   $ setIndentStrategy (const Align)
   $ basicPrint sAtom
 
+>>> decode myLangParser "(+ (* 2 20) 10) (* 10 10)"
+[EOp Add (EOp Mul (ENum 2) (ENum 20)) (ENum 10),EOp Mul (ENum 10) (ENum 10)]
 ~~~~
 
 Keep in mind that you often won't need to write all this by hand,

+ 88 - 0
example/example.hs

@@ -0,0 +1,88 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Control.Applicative ((<|>))
+import Data.Char (isDigit)
+import Data.SCargot
+import Data.SCargot.Repr.Basic
+import Data.Text (Text, pack)
+import Numeric (readHex)
+import System.Environment (getArgs)
+import Text.Parsec (anyChar, char, digit, many1, manyTill, newline, satisfy, string)
+import Text.Parsec.Text (Parser)
+
+-- Our operators are going to represent addition, subtraction, or
+-- multiplication
+data Op = Add | Sub | Mul deriving (Eq, Show)
+
+-- The atoms of our language are either one of the aforementioned
+-- operators, or positive integers
+data Atom = AOp Op | ANum Int deriving (Eq, Show)
+
+-- Once parsed, our language will consist of the applications of
+-- binary operators with literal integers at the leaves
+data Expr = EOp Op Expr Expr | ENum Int deriving (Eq, Show)
+
+-- Conversions to and from our Expr type
+toExpr :: SExpr Atom -> Either String Expr
+toExpr (A (AOp op) ::: l ::: r ::: Nil) = EOp op <$> toExpr l <*> toExpr r
+toExpr (A (ANum n)) = pure (ENum n)
+toExpr sexpr = Left ("Unable to parse expression: " ++ show sexpr)
+
+fromExpr :: Expr -> SExpr Atom
+fromExpr (EOp op l r) = A (AOp op) ::: fromExpr l ::: fromExpr r ::: Nil
+fromExpr (ENum n)     = A (ANum n) ::: Nil
+
+-- Parser and serializer for our Atom type
+pAtom :: Parser Atom
+pAtom = ((ANum . read) <$> many1 digit)
+     <|> (char '+' *> pure (AOp Add))
+     <|> (char '-' *> pure (AOp Sub))
+     <|> (char '*' *> pure (AOp Mul))
+
+sAtom :: Atom -> Text
+sAtom (AOp Add) = "+"
+sAtom (AOp Sub) = "-"
+sAtom (AOp Mul) = "*"
+sAtom (ANum n)  = pack (show n)
+
+-- Our comment syntax is going to be Haskell-like:
+hsComment :: Parser ()
+hsComment = string "--" >> manyTill anyChar newline >> return ()
+
+-- Our custom reader macro: grab the parse stream and read a
+-- hexadecimal number from it:
+hexReader :: Reader Atom
+hexReader _ = (A . ANum . rd) <$> many1 (satisfy isHexDigit)
+  where isHexDigit c = isDigit c || c `elem` hexChars
+        rd = fst . head . readHex
+        hexChars :: String
+        hexChars = "AaBbCcDdEeFf"
+
+-- Our final s-expression parser and printer:
+myLangParser :: SExprParser Atom Expr
+myLangParser
+  = setComment hsComment        -- set comment syntax to be Haskell-style
+  $ addReader '#' hexReader     -- add hex reader
+  $ setCarrier toExpr           -- convert final repr to Expr
+  $ mkParser pAtom              -- create spec with Atom type
+
+mkLangPrinter :: SExprPrinter Atom Expr
+mkLangPrinter
+  = setFromCarrier fromExpr
+  $ setIndentStrategy (const Align)
+  $ basicPrint sAtom
+
+
+main :: IO ()
+main = do
+  sExprText <- pack . head <$> getArgs
+  either putStrLn print (decode myLangParser sExprText)
+
+{-
+Exmaple usage:
+
+$ dist/build/example/example "$(echo -e '(+ (* 2 20) 10) (* 10 10)')"
+[EOp Add (EOp Mul (ENum 2) (ENum 20)) (ENum 10),EOp Mul (ENum 10) (ENum 10)]
+-}

+ 11 - 0
s-cargot.cabal

@@ -42,3 +42,14 @@ library
   default-language:    Haskell2010
   default-extensions:  CPP
   ghc-options:         -Wall
+
+executable example
+  hs-source-dirs:      example
+  main-is:             example.hs
+  build-depends:       base        >=4.7 && <5,
+                       containers  >=0.5 && <1,
+                       parsec      >=3.1 && <4,
+                       s-cargot               ,
+                       text        >=1.2 && <2
+  default-language:    Haskell2010
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N