diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+### Version 0.1.2.2
+
+* Update dependencies upper bounds
+
 ### Version 0.1.2.1
 
 * Didn't export unwrap utility
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -101,7 +101,37 @@
 1. The `arith` language from [Types and Programming Languages][tapl]: https://github.com/chiroptical/snail-arith/blob/main/src/Lib.hs
 2. Languages from [essentials-of-compilation][essentials-of-compilation]: https://github.com/chiroptical/essentials-of-compilation (each chapter is a module)
 
+## Differences from S-Cargot
+
+I was recently reminded of [s-cargot][s-cargot]. From their GitHub,
+
+> S-Cargot is a library for parsing and emitting S-expressions, designed to be
+> flexible, customizable, and extensible.
+
+This is quite different from Snail. Snail is not flexible, customizable, or
+extensible. I have chosen a syntax and either you use it or you don't.
+With S-Cargot, you can build a custom S-expression parser. Snail provides one.
+
+I don't think you can re-write Snail using S-Cargot? It doesn't appear to
+support `'(x)` or `(let [x 10] x)`. Please correct me if I missed something.
+
+I tried to mimic their example
+(https://github.com/aisamanra/s-cargot/blob/master/example/example.hs) in
+./example/Main.hs.
+
+## Resources for implementing interpreters and compilers
+
+These are resources I am personally interested in exploring, there are **many** others
+
+- [Types and Programming Languages][tapl]
+- [Essentials of Compilation][essentials-of-compilation]
+- [Compiler Design][cs4410]
+- [Compiler Construction][cse131]
+
 [tapl]: https://www.cis.upenn.edu/~bcpierce/tapl
 [haskell-parse-issue]: https://twitter.com/chiroptical/status/1471568781906518018
 [pl-wikipedia]: https://en.wikipedia.org/wiki/Programming_language
 [essentials-of-compilation]: https://mitpress.mit.edu/9780262047760/essentials-of-compilation
+[s-cargot]: https://github.com/aisamanra/s-cargot
+[cs4410]: https://course.ccs.neu.edu/cs4410sp21/
+[cse131]: https://ucsd-cse131-f19.github.io/
diff --git a/example/Main.hs b/example/Main.hs
new file mode 100644
--- /dev/null
+++ b/example/Main.hs
@@ -0,0 +1,59 @@
+module Main where
+
+import Snail
+import Control.Monad.Except
+import Data.Text (Text)
+import Data.Text qualified as Text
+import Text.Read (readMaybe)
+
+data Operation = Addition | Multiplication 
+  deriving (Eq, Show)
+
+data Ast
+  = AstInt Integer
+  | AstOperation Operation Ast Ast
+  deriving (Eq, Show)
+
+data LangError 
+  = UnknownLexeme Text
+  | UnknownOperation Text
+  | TextLiteralUnsupported
+  | EmptyExpression
+  deriving (Eq, Show)
+
+parseLeaf :: (MonadError LangError m) => Text -> m Ast
+parseLeaf = \case
+  txt ->
+    case readMaybe @Integer $ Text.unpack txt of
+      Nothing -> throwError $ UnknownLexeme txt
+      Just int -> pure $ AstInt int
+
+parseOp :: (MonadError LangError m) => Text -> m Operation
+parseOp = \case
+  "+" -> pure Addition
+  "*" -> pure Multiplication
+  txt -> throwError $ UnknownOperation txt
+
+fromSnail :: (MonadError LangError m) => SnailAst -> m Ast
+fromSnail = \case
+  -- no text literals are supported in this language
+  TextLiteral _ -> throwError TextLiteralUnsupported
+  -- `X` where `X` is a leaf in 'Ast'
+  Lexeme (_, leaf) -> parseLeaf leaf
+  SExpression _ _ [Lexeme (_, txt), argumentOne, argumentTwo] -> do
+    op <- parseOp txt
+    one <- fromSnail argumentOne
+    two <- fromSnail argumentTwo
+    pure $ AstOperation op one two
+  -- empty expressions are invalid
+  SExpression _ _ [] -> throwError EmptyExpression
+  -- expression of expressions, e.g. `((X))` -> `(X)`
+  SExpression leading fence exprs ->
+    fromSnail . unwrap . SExpression leading fence $ unwrap <$> exprs
+
+main :: IO ()
+main = do
+  case parseSnail "(+ 1 2)" of
+    Left err -> print $ "Unable to parse snail: " <> show err
+    Right [snail] -> runExceptT (fromSnail snail) >>= print
+    Right _ -> putStrLn "Excepted single expression"
diff --git a/snail.cabal b/snail.cabal
--- a/snail.cabal
+++ b/snail.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.35.2.
+-- This file has been generated from package.yaml by hpack version 0.38.3.
 --
 -- see: https://github.com/sol/hpack
 
 name:           snail
-version:        0.1.2.1
+version:        0.1.2.2
 synopsis:       A programming language with no semantics
 description:    An s-expression parser and abstract syntax tree for a programming language with no semantics. If you wanted to write an interpreter or compiler you convert the AST into your own.
 category:       Parsing
@@ -51,19 +51,44 @@
   hs-source-dirs:
       src
   default-extensions:
+      FlexibleContexts
       ImportQualifiedPost
       LambdaCase
       OverloadedStrings
+      TypeApplications
   build-depends:
-      QuickCheck >=2.14.3 && <2.15
+      QuickCheck >=2.14.3 && <2.20
     , base >=4.15 && <5
-    , containers >=0.6.7 && <0.7
-    , megaparsec >=9.3.1 && <9.4
-    , mtl >=2.2.2 && <2.3
-    , text >=2.0.2 && <2.1
-    , text-display >=0.0.5 && <0.1
+    , containers >=0.6.7 && <0.8
+    , megaparsec >=9.5.0 && <9.9
+    , mtl >=2.3.1 && <2.4
+    , text >=2.0.2 && <2.2
+    , text-display >=0.0.5 && <0.1 || >=1.0 && <1.1
   default-language: Haskell2010
 
+executable snail
+  main-is: Main.hs
+  other-modules:
+      Paths_snail
+  hs-source-dirs:
+      example
+  default-extensions:
+      FlexibleContexts
+      ImportQualifiedPost
+      LambdaCase
+      OverloadedStrings
+      TypeApplications
+  build-depends:
+      QuickCheck >=2.14.3 && <2.20
+    , base >=4.15 && <5
+    , containers >=0.6.7 && <0.8
+    , megaparsec >=9.5.0 && <9.9
+    , mtl >=2.3.1 && <2.4
+    , snail
+    , text >=2.0.2 && <2.2
+    , text-display >=0.0.5 && <0.1 || >=1.0 && <1.1
+  default-language: Haskell2010
+
 test-suite snail-test
   type: exitcode-stdio-1.0
   main-is: Spec.hs
@@ -76,21 +101,23 @@
   hs-source-dirs:
       test
   default-extensions:
+      FlexibleContexts
       ImportQualifiedPost
       LambdaCase
       OverloadedStrings
+      TypeApplications
   ghc-options: -threaded -rtsopts -with-rtsopts=-N
   build-depends:
       HUnit >=1.6.2 && <1.7
-    , QuickCheck >=2.14.3 && <2.15
+    , QuickCheck >=2.14.3 && <2.20
     , base >=4.15 && <5
-    , containers >=0.6.7 && <0.7
-    , hspec >=2.10.10 && <2.11
-    , hspec-discover >=2.10.10 && <2.11
-    , megaparsec >=9.3.1 && <9.4
-    , mtl >=2.2.2 && <2.3
+    , containers >=0.6.7 && <0.8
+    , hspec >=2.11.8 && <2.12
+    , hspec-discover >=2.11.8 && <2.12
+    , megaparsec >=9.5.0 && <9.9
+    , mtl >=2.3.1 && <2.4
     , raw-strings-qq ==1.1.*
     , snail
-    , text >=2.0.2 && <2.1
-    , text-display >=0.0.5 && <0.1
+    , text >=2.0.2 && <2.2
+    , text-display >=0.0.5 && <0.1 || >=1.0 && <1.1
   default-language: Haskell2010
diff --git a/src/Snail/Lexer.hs b/src/Snail/Lexer.hs
--- a/src/Snail/Lexer.hs
+++ b/src/Snail/Lexer.hs
@@ -114,7 +114,7 @@
  recursively separated by 'spaces' in 'sExpression'.
 -}
 leaves :: Parser SnailAst
-leaves = lexeme <|> textLiteral <|> sExpression
+leaves = try sExpression <|> lexeme <|> textLiteral
 
 -- | Parse an 'SExpression'
 sExpression :: Parser SnailAst
diff --git a/test/Snail/LexerSpec.hs b/test/Snail/LexerSpec.hs
--- a/test/Snail/LexerSpec.hs
+++ b/test/Snail/LexerSpec.hs
@@ -160,3 +160,15 @@
 
         it "fails to parse nested mismatched brackets" $ do
             parseMaybe snailAst "([)]" `shouldSatisfy` isNothing
+
+        it "associates inner '#' with the s-expression" $ do
+            let Just [result] = parseMaybe snailAst "(different-char/2 #(inside))"
+            foldLexemes result `shouldBe` ["different-char/2", "inside"]
+
+        it "fails with two leading characters" $ do
+            parseMaybe snailAst "@,(foo)" `shouldSatisfy` isNothing
+
+        -- NOTE: this may or may not be the desired behavior
+        it "parses two leading characters as valid lexeme" $ do
+            let Just [result] = parseMaybe snailAst "(@,(foo ...))"
+            foldLexemes result `shouldBe` ["@,", "foo", "..."]
