diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# 0.2.1.0
+
+  * Add `fp` builtin
+  * Add `:` unary operator
+  * Floor/ceiling operators
+  * `Some` and `None` literals
+
 # 0.2.0.0
 
   * Complete implementation of folds/maps for lists
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,6 +3,10 @@
 
 # Installation
 
+## Releases
+
+There are binaries for some platforms on the [releases page](https://github.com/vmchale/jacinda/releases/).
+
 ## From Source
 
 First, install [Rust's regex library](https://github.com/rust-lang/regex/tree/master/regex-capi#c-api-for-rusts-regex-engine). You'll need to put `librure.so` or `librure.dylib` etc. in the appropriate place.
@@ -13,6 +17,10 @@
 cabal install jacinda
 ```
 
+## Vim Plugin
+
+There is a [vim plugin](https://github.com/vmchale/jacinda-vim).
+
 # SHOCK & AWE
 
 ```
@@ -21,7 +29,7 @@
 
 ```
 curl -sL https://raw.githubusercontent.com/nychealth/coronavirus-data/master/latest/now-weekly-breakthrough.csv | \
-    ja ',[1.0-x%y] {ix>1}{`5:f} {ix>1}{`11:f}' -F,
+    ja ',[1.0-x%y] {ix>1}{`5:} {ix>1}{`11:}' -F,
 ```
 
 # Documentation
@@ -52,6 +60,7 @@
   * Type system is questionable
   * Postfix `:f` and `:i` are handled poorly
   * File imports/includes
+  * Various bugs in evaluation with regular expressions
 
 Intentionally missing features:
 
diff --git a/doc/guide.pdf b/doc/guide.pdf
Binary files a/doc/guide.pdf and b/doc/guide.pdf differ
diff --git a/jacinda.cabal b/jacinda.cabal
--- a/jacinda.cabal
+++ b/jacinda.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.0
 name:               jacinda
-version:            0.2.0.0
+version:            0.2.1.0
 license:            AGPL-3
 license-file:       COPYING
 maintainer:         vamchale@gmail.com
@@ -24,6 +24,11 @@
     type:     git
     location: https://github.com/vmchale/jacinda
 
+flag cross
+    description: Enable to ease cross-compiling
+    default:     False
+    manual:      True
+
 library jacinda-lib
     exposed-modules:
         Jacinda.Parser
@@ -34,8 +39,7 @@
         Jacinda.Regex
         Jacinda.File
 
-    build-tool-depends: alex:alex, happy:happy
-    hs-source-dirs:     src
+    hs-source-dirs:   src
     other-modules:
         Jacinda.Lexer
         Intern.Name
@@ -45,9 +49,10 @@
         Jacinda.Backend.TreeWalk
         Jacinda.Backend.Printf
         Data.List.Ext
+        Data.Vector.Ext
 
-    default-language:   Haskell2010
-    ghc-options:        -Wall -O2
+    default-language: Haskell2010
+    ghc-options:      -Wall -O2
     build-depends:
         base >=4.10.0.0 && <5,
         bytestring >=0.11.0.0,
@@ -62,6 +67,9 @@
         microlens-mtl,
         vector,
         recursion >=1.0.0.0
+
+    if !flag(cross)
+        build-tool-depends: alex:alex, happy:happy
 
     if impl(ghc >=8.0)
         ghc-options:
diff --git a/man/ja.1 b/man/ja.1
--- a/man/ja.1
+++ b/man/ja.1
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pandoc 2.16.2
+.\" Automatically generated by Pandoc 2.17
 .\"
 .TH "ja (1)" "" "" "" ""
 .hy
@@ -42,6 +42,8 @@
 .PP
 \f[B]:f\f[R] Postfix operator: parse float
 .PP
+\f[B]:\f[R] Postfix operator: parse, inferring type
+.PP
 \f[B]#\f[R] Prefix operator: tally (count bytes in string)
 .TP
 \f[B],\f[R] Ternary operator: zip with
@@ -62,7 +64,7 @@
 \f[B]#.\f[R] Binary operator: filter
 (a -> Bool) -> Stream a -> Stream a
 .TP
-\f[B].\f[R] Binary operator: prior
+\f[B]\[rs].\f[R] Binary operator: prior
 (a -> a -> a) -> Stream a -> Stream a
 .PP
 \f[B]max\f[R] Maximum of two values
@@ -90,10 +92,10 @@
 \f[B]splitc\f[R] Split a string on a single character
 Str -> Str -> List Str
 .TP
-\f[B]floor\f[R] Floor function
+\f[B]|.\f[R] Floor function
 Float -> Int
 .TP
-\f[B]ceil\f[R] Ceiling function
+\f[B]|\[ga]\f[R] Ceiling function
 Float -> Int
 .PP
 \f[B]sprintf\f[R] Convert an expression to a string using the format
@@ -105,6 +107,8 @@
 \f[B]match\f[R]
 Str -> Regex -> Option (Int .
 Int)
+.PP
+\f[B]fp\f[R] Filename
 .SS SYNTAX
 .PP
 \f[B]\[ga]n\f[R] nth field
@@ -127,6 +131,8 @@
 List a -> a
 .PP
 \f[B]->n\f[R] Get the nth element of a tuple
+.PP
+\f[B]{.\f[R] Line comment
 .SH BUGS
 .PP
 Please report any bugs you may come across to
diff --git a/src/Data/Vector/Ext.hs b/src/Data/Vector/Ext.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Vector/Ext.hs
@@ -0,0 +1,7 @@
+module Data.Vector.Ext ( priorM_
+                       ) where
+
+import qualified Data.Vector as V
+
+priorM_ :: Monad m => (a -> a -> m b) -> V.Vector a -> m ()
+priorM_ op xs = V.zipWithM_ op (V.tail xs) xs
diff --git a/src/Jacinda/AST.hs b/src/Jacinda/AST.hs
--- a/src/Jacinda/AST.hs
+++ b/src/Jacinda/AST.hs
@@ -87,6 +87,7 @@
     pretty (TyVar _ n)      = pretty n
     pretty (TyArr _ ty ty') = pretty ty <+> "⟶" <+> pretty ty'
     pretty (TyTup _ tys)    = jacTup tys
+    pretty (TyNamed _ tn)   = pretty tn
 
 instance Show (T a) where
     show = show . pretty
@@ -99,8 +100,10 @@
          | Select Int
          | IParse
          | FParse
+         | Parse
          | Floor
          | Ceiling
+         | Some
          deriving (Eq)
 
 instance Pretty BUn where
@@ -113,6 +116,8 @@
     pretty FParse     = ":f"
     pretty Floor      = "floor"
     pretty Ceiling    = "ceil"
+    pretty Parse      = ":"
+    pretty Some       = "Some"
 
 -- ternary
 data BTer = ZipW
@@ -189,6 +194,8 @@
 
 -- 0-ary
 data N = Ix
+       | None
+       | Fp
        deriving (Eq)
 
 -- expression
@@ -264,6 +271,8 @@
 
 instance Pretty N where
     pretty Ix   = "ix"
+    pretty None = "None"
+    pretty Fp   = "fp"
 
 instance Pretty (E a) where
     pretty (Column _ i)                                            = "$" <> pretty i
@@ -291,6 +300,7 @@
     pretty (EApp _ (UBuiltin _ (Select i)) e)                      = pretty e <> "->" <> pretty i
     pretty (EApp _ (UBuiltin _ IParse) e')                         = pretty e' <> ":i"
     pretty (EApp _ (UBuiltin _ FParse) e')                         = pretty e' <> ":f"
+    pretty (EApp _ (UBuiltin _ Parse) e')                          = pretty e' <> ":"
     pretty (EApp _ e@UBuiltin{} e')                                = pretty e <> pretty e'
     pretty (EApp _ e e')                                           = pretty e <+> pretty e'
     pretty (Var _ n)                                               = pretty n
@@ -313,7 +323,7 @@
     pretty (Let _ (n, b) e)                                        = "let" <+> "val" <+> pretty n <+> ":=" <+> pretty b <+> "in" <+> pretty e <+> "end"
     pretty (Paren _ e)                                             = parens (pretty e)
     pretty (Arr _ es)                                              = tupledByFunky "," (V.toList $ pretty <$> es)
-    pretty (OptionVal  _ (Just e))                                 = "Some" <+> pretty e
+    pretty (OptionVal _ (Just e))                                  = "Some" <+> pretty e
     pretty (OptionVal _ Nothing)                                   = "None"
 
 instance Show (E a) where
diff --git a/src/Jacinda/Backend/Normalize.hs b/src/Jacinda/Backend/Normalize.hs
--- a/src/Jacinda/Backend/Normalize.hs
+++ b/src/Jacinda/Backend/Normalize.hs
@@ -169,7 +169,7 @@
 eNorm e@BBuiltin{}    = pure e
 eNorm e@TBuiltin{}    = pure e
 eNorm (Tup tys es)    = Tup tys <$> traverse eNorm es
-eNorm e@(NBuiltin _ Ix) = pure e
+eNorm e@NBuiltin{}    = pure e
 eNorm (EApp ty op@BBuiltin{} e) = EApp ty op <$> eNorm e
 eNorm (EApp ty (EApp ty' op@(BBuiltin _ Matches) e) e') = do
     eI <- eNorm e
@@ -408,6 +408,19 @@
     pure $ case eI of
         (StrLit _ str) -> parseAsF str
         _              -> EApp ty op eI
+eNorm (EApp ty op@(UBuiltin (TyArr _ _ (TyB _ TyFloat)) Parse) e) = do
+    eI <- eNorm e
+    pure $ case eI of
+        (StrLit _ str) -> parseAsF str
+        _              -> EApp ty op eI
+eNorm (EApp ty op@(UBuiltin (TyArr _ _ (TyB _ TyInteger)) Parse) e) = do
+    eI <- eNorm e
+    pure $ case eI of
+        (StrLit _ str) -> parseAsEInt str
+        _              -> EApp ty op eI
+eNorm (EApp ty op@(UBuiltin _ Some) e) = do
+    eI <- eNorm e
+    pure $ OptionVal ty (Just eI)
 eNorm Dfn{} = desugar
 eNorm ResVar{} = desugar
 eNorm (Let _ (Name _ (Unique i) _, b) e) = do
diff --git a/src/Jacinda/Backend/TreeWalk.hs b/src/Jacinda/Backend/TreeWalk.hs
--- a/src/Jacinda/Backend/TreeWalk.hs
+++ b/src/Jacinda/Backend/TreeWalk.hs
@@ -5,6 +5,7 @@
 -- TODO: normalize before mapping?
 
 import           Control.Exception         (Exception, throw)
+import           Control.Recursion         (cata, embed)
 import qualified Data.ByteString           as BS
 import           Data.Foldable             (foldl', traverse_)
 import           Data.List                 (scanl')
@@ -25,6 +26,8 @@
                  | IndexOutOfBounds Int
                  deriving (Show)
 
+type FileBS = BS.ByteString
+
 instance Exception StreamError where
 
 (!) :: V.Vector a -> Int -> a
@@ -64,11 +67,16 @@
 
 -- TODO: do I want to interleave state w/ eNorm or w/e
 
+withFp :: FileBS -> E (T K) -> E (T K)
+withFp fp = cata a where
+    a (NBuiltinF _ Fp) = mkStr fp
+    a x                = embed x
+
 -- eval
-eEval :: (Int, BS.ByteString, V.Vector BS.ByteString) -- ^ Field context (for that line)
+eEval :: (FileBS, Int, BS.ByteString, V.Vector BS.ByteString) -- ^ Field context (for that line)
       -> E (T K)
       -> E (T K)
-eEval (ix, line, ctx) = go where
+eEval (fp, ix, line, ctx) = go where
     go b@BoolLit{} = b
     go i@IntLit{} = i
     go f@FloatLit{} = f
@@ -80,6 +88,7 @@
     go op@TBuiltin{} = op
     go (EApp ty op@BBuiltin{} e) = EApp ty op (go e)
     go (NBuiltin _ Ix) = mkI (fromIntegral ix)
+    go (NBuiltin _ Fp) = mkStr fp
     go AllField{} = StrLit tyStr line
     go (Field _ i) = StrLit tyStr (ctx ! (i-1)) -- cause vector indexing starts at 0
     go (EApp _ (UBuiltin _ IParse) e) =
@@ -88,6 +97,12 @@
     go (EApp _ (UBuiltin _ FParse) e) =
         let eI = asStr (go e)
             in parseAsF eI
+    go (EApp _ (UBuiltin (TyArr _ _ (TyB _ TyInteger)) Parse) e) =
+        let eI = asStr (go e)
+            in parseAsEInt eI
+    go (EApp _ (UBuiltin (TyArr _ _ (TyB _ TyFloat)) Parse) e) =
+        let eI = asStr (go e)
+            in parseAsF eI
     go (EApp _ (EApp _ (BBuiltin _ Matches) e) e') =
         let eI = go e
             eI' = go e'
@@ -261,12 +276,11 @@
               applyOp' op e e' = go (EApp undefined (EApp undefined op e) e')
     go (Arr ty es) = Arr ty (go <$> es)
 
-applyOp :: Int
-        -> E (T K) -- ^ Operator
+applyOp :: E (T K) -- ^ Operator
         -> E (T K)
         -> E (T K)
         -> E (T K)
-applyOp i op e e' = eClosed i (EApp undefined (EApp undefined op e) e') -- FIXME: undefined is ??
+applyOp op e e' = eClosed undefined (EApp undefined (EApp undefined op e) e') -- FIXME: undefined is ??
 
 atField :: RurePtr
         -> Int
@@ -274,87 +288,88 @@
         -> BS.ByteString
 atField re i = (! (i-1)) . splitBy re
 
-mkCtx :: RurePtr -> Int -> BS.ByteString -> (Int, BS.ByteString, V.Vector BS.ByteString)
-mkCtx re ix line = (ix, line, splitBy re line)
+mkCtx :: FileBS -> RurePtr -> Int -> BS.ByteString -> (FileBS, Int, BS.ByteString, V.Vector BS.ByteString)
+mkCtx fp re ix line = (fp, ix, line, splitBy re line)
 
-applyUn :: Int
-        -> E (T K)
+applyUn :: E (T K)
         -> E (T K)
         -> E (T K)
-applyUn i unOp e =
+applyUn unOp e =
     case eLoc unOp of
-        TyArr _ _ res -> eClosed i (EApp res unOp e)
+        TyArr _ _ res -> eClosed undefined (EApp res unOp e)
         _             -> error "Internal error?"
 
 -- | Turn an expression representing a stream into a stream of expressions (using line as context)
-ir :: RurePtr
-   -> Int
+ir :: FileBS
+   -> RurePtr
    -> E (T K)
    -> [BS.ByteString]
    -> [E (T K)] -- TODO: include chunks/context too?
 ir _ _ AllColumn{} = fmap mkStr
-ir re _ (Column _ i) = fmap (mkStr . atField re i)
-ir re _ (IParseCol _ i) = fmap (parseAsEInt . atField re i)
-ir re _ (FParseCol _ i) = fmap (parseAsF . atField re i)
-ir re _ (Implicit _ e) =
+ir _ re (Column _ i) = fmap (mkStr . atField re i)
+ir _ re (IParseCol _ i) = fmap (parseAsEInt . atField re i)
+ir _ re (FParseCol _ i) = fmap (parseAsF . atField re i)
+ir fp re (Implicit _ e) =
     let e' = compileR e
-        in imap (\ix line -> eEval (mkCtx re ix line) e')
-ir re _ (Guarded _ pe e) =
+        in imap (\ix line -> eEval (mkCtx fp re ix line) e')
+ir fp re (Guarded _ pe e) =
     let pe' = compileR pe
         e' = compileR e
     -- FIXME: compile e too?
     -- TODO: normalize before stream
-        in imap (\ix line -> eEval (mkCtx re ix line) e') . ifilter (\ix line -> asBool (eEval (mkCtx re ix line) pe'))
-ir re i (EApp _ (EApp _ (BBuiltin _ Map) op) stream) = let op' = compileR op in fmap (applyUn i op') . ir re i stream
-ir re i (EApp _ (EApp _ (BBuiltin _ Filter) op) stream) =
-    let op' = compileR op
-        in filter (asBool . applyUn i op') . ir re i stream
-ir re i (EApp _ (EApp _ (BBuiltin _ Prior) op) stream) = prior (applyOp i op) . ir re i stream
-ir re i (EApp _ (EApp _ (EApp _ (TBuiltin _ ZipW) op) streaml) streamr) = \lineStream ->
+        in imap (\ix line -> eEval (mkCtx fp re ix line) e') . ifilter (\ix line -> asBool (eEval (mkCtx fp re ix line) pe'))
+ir fp re (EApp _ (EApp _ (BBuiltin _ Map) op) stream) = let op' = compileR (withFp fp op) in fmap (applyUn op') . ir fp re stream
+ir fp re (EApp _ (EApp _ (BBuiltin _ Filter) op) stream) =
+    let op' = compileR (withFp fp op)
+        in filter (asBool . applyUn op') . ir fp re stream
+ir fp re (EApp _ (EApp _ (BBuiltin _ Prior) op) stream) = prior (applyOp (withFp fp op)) . ir fp re stream
+ir fp re (EApp _ (EApp _ (EApp _ (TBuiltin _ ZipW) op) streaml) streamr) = \lineStream ->
     let
-        irl = ir re i streaml lineStream
-        irr = ir re i streamr lineStream
-    in zipWith (applyOp i op) irl irr
-ir re i (EApp _ (EApp _ (EApp _ (TBuiltin _ Scan) op) seed) xs) =
-    scanl' (applyOp i op) seed . ir re i xs
+        irl = ir fp re streaml lineStream
+        irr = ir fp re streamr lineStream
+    in zipWith (applyOp (withFp fp op)) irl irr
+ir fp re (EApp _ (EApp _ (EApp _ (TBuiltin _ Scan) op) seed) xs) =
+    scanl' (applyOp (withFp fp op)) seed . ir fp re xs
 
 -- | Output stream that prints each entry (expression)
 printStream :: [E (T K)] -> IO ()
 printStream = traverse_ print
 
-foldWithCtx :: RurePtr -> Int
+foldWithCtx :: FileBS
+            -> RurePtr
             -> E (T K)
             -> E (T K)
             -> E (T K)
             -> [BS.ByteString]
             -> E (T K)
-foldWithCtx re i op seed streamExpr = foldl' (applyOp i op) seed . ir re i streamExpr
+foldWithCtx fp re op seed streamExpr = foldl' (applyOp op) seed . ir fp re streamExpr
 
-runJac :: RurePtr -- ^ Record separator
+runJac :: FileBS
+       -> RurePtr -- ^ Record separator
        -> Int
        -> Program (T K)
        -> Either StreamError ([BS.ByteString] -> IO ())
-runJac re i e = fileProcessor re i (closedProgram i e)
+runJac fp re i e = fileProcessor fp re (closedProgram i e)
 
 -- evaluate something that has a fold nested in it
-eWith :: RurePtr -> Int -> E (T K) -> [BS.ByteString] -> E (T K)
-eWith re i (EApp _ (EApp _ (EApp _ (TBuiltin (TyArr _ _ (TyArr _ _ (TyArr _ (TyApp _ (TyB _ TyStream) _) _))) Fold) op) seed) stream) = foldWithCtx re i op seed stream
-eWith re i (EApp ty e0 e1)                                             = \bs -> eClosed i (EApp ty (eWith re i e0 bs) (eWith re i e1 bs))
-eWith _ _ e@BBuiltin{}                                                 = const e
-eWith _ _ e@UBuiltin{}                                                 = const e
-eWith _ _ e@TBuiltin{}                                                 = const e
-eWith _ _ e@StrLit{}                                                   = const e
-eWith _ _ e@FloatLit{}                                                 = const e
-eWith _ _ e@IntLit{}                                                   = const e
-eWith _ _ e@BoolLit{}                                                  = const e
-eWith re i (Tup ty es)                                                 = \bs -> Tup ty ((\e -> eWith re i e bs) <$> es)
+eWith :: FileBS -> RurePtr -> E (T K) -> [BS.ByteString] -> E (T K)
+eWith fp re (EApp _ (EApp _ (EApp _ (TBuiltin (TyArr _ _ (TyArr _ _ (TyArr _ (TyApp _ (TyB _ TyStream) _) _))) Fold) op) seed) stream) = foldWithCtx fp re op seed stream
+eWith fp re (EApp ty e0 e1)                                                                                                            = \bs -> eClosed undefined (EApp ty (eWith fp re e0 bs) (eWith fp re e1 bs))
+eWith _ _ e@BBuiltin{}                                                                                                                = const e
+eWith _ _ e@UBuiltin{}                                                                                                                = const e
+eWith _ _ e@TBuiltin{}                                                                                                                = const e
+eWith _ _ e@StrLit{}                                                                                                                  = const e
+eWith _ _ e@FloatLit{}                                                                                                                = const e
+eWith _ _ e@IntLit{}                                                                                                                  = const e
+eWith _ _ e@BoolLit{}                                                                                                                 = const e
+eWith fp re (Tup ty es)                                                                                                                = \bs -> Tup ty ((\e -> eWith fp re e bs) <$> es)
+eWith fp re (OptionVal ty e)                                                                                                           = \bs -> OptionVal ty ((\eϵ -> eWith fp re eϵ bs) <$> e)
+-- TODO: rewrite tuple-of-folds as fold-of-tuples ... "compile" to E (T K) -> E (T K)
+-- OR "compile" to [(Int, E (T K)] -> ...
 
--- TODO: passing in 'i' separately to each eClosed is sketch but... hopefully
--- won't blow up in our faces
---
 -- | Given an expression, turn it into a function which will process the file.
-fileProcessor :: RurePtr
-              -> Int
+fileProcessor :: FileBS
+              -> RurePtr
               -> E (T K)
               -> Either StreamError ([BS.ByteString] -> IO ())
 fileProcessor _ _ AllField{}    = Left NakedField
@@ -362,37 +377,37 @@
 fileProcessor _ _ (NBuiltin _ Ix) = Left NakedField
 fileProcessor _ _ AllColumn{} = Right $ \inp ->
     printStream $ fmap mkStr inp
-fileProcessor re _ (Column _ i) = Right $ \inp -> do
+fileProcessor _ re (Column _ i) = Right $ \inp -> do
     printStream $ fmap (mkStr . atField re i) inp
-fileProcessor re _ (IParseCol _ i) = Right $ \inp -> do
+fileProcessor _ re (IParseCol _ i) = Right $ \inp -> do
     printStream $ fmap (parseAsEInt . atField re i) inp
-fileProcessor re _ (FParseCol _ i) = Right $ \inp -> do
+fileProcessor _ re (FParseCol _ i) = Right $ \inp -> do
     printStream $ fmap (parseAsF . atField re i) inp
--- TODO: this should extract any regex and compile them, use io/low-level API...
-fileProcessor re i e@Guarded{} = Right $ \inp -> do
-    printStream $ ir re i e inp
-fileProcessor re i e@Implicit{} = Right $ \inp -> do
-    printStream $ ir re i e inp
-fileProcessor re i e@(EApp _ (EApp _ (BBuiltin _ Filter) _) _) = Right $ \inp -> do
-    printStream $ ir re i e inp
-fileProcessor re i e@(EApp _ (EApp _ (BBuiltin (TyArr _ _ (TyArr _ _ (TyApp _ (TyB _ TyStream) _))) Map) _) _) = Right $ \inp -> do
-    printStream $ ir re i e inp
-fileProcessor re i e@(EApp _ (EApp _ (BBuiltin _ Prior) _) _) = Right $ \inp -> do
-    printStream $ ir re i e inp
-fileProcessor re i e@(EApp _ (EApp _ (EApp _ (TBuiltin _ Scan) _) _) _) = Right $ \inp -> do
-    printStream $ ir re i e inp
-fileProcessor re i e@(EApp _ (EApp _ (EApp _ (TBuiltin _ ZipW) _) _) _) = Right $ \inp -> do
-    printStream $ ir re i e inp
+fileProcessor fp re e@Guarded{} = Right $ \inp -> do
+    printStream $ ir fp re e inp
+fileProcessor fp re e@Implicit{} = Right $ \inp -> do
+    printStream $ ir fp re e inp
+fileProcessor fp re e@(EApp _ (EApp _ (BBuiltin _ Filter) _) _) = Right $ \inp -> do
+    printStream $ ir fp re e inp
+fileProcessor fp re e@(EApp _ (EApp _ (BBuiltin (TyArr _ _ (TyArr _ _ (TyApp _ (TyB _ TyStream) _))) Map) _) _) = Right $ \inp -> do
+    printStream $ ir fp re e inp
+fileProcessor fp re e@(EApp _ (EApp _ (BBuiltin _ Prior) _) _) = Right $ \inp -> do
+    printStream $ ir fp re e inp
+fileProcessor fp re e@(EApp _ (EApp _ (EApp _ (TBuiltin _ Scan) _) _) _) = Right $ \inp -> do
+    printStream $ ir fp re e inp
+fileProcessor fp re e@(EApp _ (EApp _ (EApp _ (TBuiltin _ ZipW) _) _) _) = Right $ \inp -> do
+    printStream $ ir fp re e inp
 fileProcessor _ _ Var{} = error "Internal error?"
 fileProcessor _ _ e@IntLit{} = Right $ const (print e)
 fileProcessor _ _ e@BoolLit{} = Right $ const (print e)
 fileProcessor _ _ e@StrLit{} = Right $ const (print e)
 fileProcessor _ _ e@FloatLit{} = Right $ const (print e)
 fileProcessor _ _ e@RegexLit{} = Right $ const (print e)
+fileProcessor fp _ (NBuiltin _ Fp) = Right $ const (print fp)
 fileProcessor _ _ Lam{} = Left UnevalFun
 fileProcessor _ _ Dfn{} = badSugar
 fileProcessor _ _ ResVar{} = badSugar
 fileProcessor _ _ BBuiltin{} = Left UnevalFun
 fileProcessor _ _ UBuiltin{} = Left UnevalFun
 fileProcessor _ _ TBuiltin{} = Left UnevalFun
-fileProcessor re i e = Right $ print . eWith re i e
+fileProcessor fp re e = Right $ print . eWith fp re e
diff --git a/src/Jacinda/File.hs b/src/Jacinda/File.hs
--- a/src/Jacinda/File.hs
+++ b/src/Jacinda/File.hs
@@ -11,6 +11,7 @@
 import           Control.Monad              ((<=<))
 import           Data.Bifunctor             (second)
 import qualified Data.ByteString            as BS
+import qualified Data.ByteString.Char8      as ASCII
 import qualified Data.ByteString.Lazy       as BSL
 import qualified Data.ByteString.Lazy.Char8 as ASCIIL
 import           Data.Functor               (void)
@@ -42,16 +43,17 @@
 compileFS (Just bs) = compileDefault bs
 compileFS Nothing   = defaultRurePtr
 
-runOnBytes :: BSL.ByteString -- ^ Program
+runOnBytes :: FilePath
+           -> BSL.ByteString -- ^ Program
            -> Maybe BS.ByteString -- ^ Field separator
            -> BSL.ByteString
            -> IO ()
-runOnBytes src cliFS contents =
+runOnBytes fp src cliFS contents =
     case parseWithMax' src of
         Left err -> throwIO err
         Right (ast, m) -> do
             (typed, i) <- yeetIO $ runTypeM m (tyProgram ast)
-            cont <- yeetIO $ runJac (compileFS (cliFS <|> getFS ast)) i typed
+            cont <- yeetIO $ runJac (ASCII.pack fp) (compileFS (cliFS <|> getFS ast)) i typed
             cont $ fmap BSL.toStrict (ASCIIL.lines contents)
             -- see: BSL.split, BSL.splitWith
 
@@ -59,13 +61,13 @@
             -> Maybe BS.ByteString -- ^ Field separator
             -> Handle
             -> IO ()
-runOnHandle src cliFS = runOnBytes src cliFS <=< BSL.hGetContents
+runOnHandle src cliFS = runOnBytes "(runOnBytes)" src cliFS <=< BSL.hGetContents
 
 runOnFile :: BSL.ByteString
           -> Maybe BS.ByteString
           -> FilePath
           -> IO ()
-runOnFile e fs = runOnBytes e fs <=< BSL.readFile
+runOnFile e fs fp = runOnBytes fp e fs =<< BSL.readFile fp
 
 tcIO :: BSL.ByteString -> IO ()
 tcIO = yeetIO . tyCheck
diff --git a/src/Jacinda/Lexer.x b/src/Jacinda/Lexer.x
--- a/src/Jacinda/Lexer.x
+++ b/src/Jacinda/Lexer.x
@@ -44,7 +44,7 @@
 
 $str_special = [\\\']
 
-@escape_str = \\ [$str_special n]
+@escape_str = \\ [$str_special nt]
 
 @string = \' ([^ $str_special] | @escape_str)* \'
 
@@ -83,7 +83,6 @@
 
         "|"                      { mkSym FoldTok }
         \"                       { mkSym Quot }
-        ¨                        { mkSym Quot }
         "^"                      { mkSym Caret }
 
         "="                      { mkSym EqTok }
@@ -110,6 +109,8 @@
         ";"                      { mkSym Semicolon }
         "\."                     { mkSym BackslashDot }
         \\                       { mkSym Backslash }
+        "|`"                     { mkSym CeilSym }
+        "|."                     { mkSym FloorSym }
 
         in                       { mkKw KwIn }
         let                      { mkKw KwLet }
@@ -120,7 +121,9 @@
 
         fs                       { mkRes VarFs }
         ix                       { mkRes VarIx }
-        ⍳                        { mkRes VarIx }
+        -- TODO: does this uncover an alex bug?
+        -- ⍳                        { mkRes VarIx }
+        -- ¨                        { mkSym Quot }
         min                      { mkRes VarMin }
         max                      { mkRes VarMax }
 
@@ -132,6 +135,9 @@
         floor                    { mkBuiltin BuiltinFloor }
         ceil                     { mkBuiltin BuiltinCeil }
         match                    { mkBuiltin BuiltinMatch }
+        Some                     { mkBuiltin BuiltinSome }
+        None                     { mkBuiltin BuiltinNone }
+        fp                       { mkBuiltin BuiltinFp }
 
         ":i"                     { mkBuiltin BuiltinIParse }
         ":f"                     { mkBuiltin BuiltinFParse }
@@ -150,11 +156,10 @@
         $digit+\.$digit+         { tok (\p s -> alex $ TokFloat p (read $ ASCII.unpack s)) }
         _$digit+\.$digit+        { tok (\p s -> alex $ TokFloat p (negate $ read $ ASCII.unpack $ BSL.tail s)) }
 
-        -- TODO: allow chars to be escaped
-        -- TODO: consider dropping this syntax for strings?
         @string                  { tok (\p s -> alex $ TokStr p (escReplace' $ BSL.init $ BSL.tail s)) }
 
-        "/"[^\/]*"/"             { tok (\p s -> alex $ TokRR p (BSL.init $ BSL.tail s)) } -- TODO: allow slashes that are escaped
+        -- TODO: allow chars to be escaped
+        "/"[^\/]*"/"             { tok (\p s -> alex $ TokRR p (BSL.init $ BSL.tail s)) }
 
         @name                    { tok (\p s -> TokName p <$> newIdentAlex p (mkText s)) }
         @tyname                  { tok (\p s -> TokTyName p <$> newIdentAlex p (mkText s)) }
@@ -189,7 +194,7 @@
 escReplace =
       T.replace "\\\"" "\""
     . T.replace "\\n" "\n"
-    . T.replace "\\$" "$"
+    . T.replace "\\t" "\t"
 
 mkText :: BSL.ByteString -> T.Text
 mkText = decodeUtf8 . BSL.toStrict
@@ -257,6 +262,8 @@
          | Backslash
          | BackslashDot
          | FilterTok
+         | FloorSym
+         | CeilSym
 
 instance Pretty Sym where
     pretty PlusTok       = "+"
@@ -296,6 +303,8 @@
     pretty Backslash     = "\\"
     pretty BackslashDot  = "\\."
     pretty FilterTok     = "#."
+    pretty FloorSym      = "|."
+    pretty CeilSym       = "|`"
 
 data Keyword = KwLet
              | KwIn
@@ -339,6 +348,9 @@
              | BuiltinFloor
              | BuiltinCeil
              | BuiltinMatch
+             | BuiltinSome
+             | BuiltinNone
+             | BuiltinFp
 
 instance Pretty Builtin where
     pretty BuiltinIParse  = ":i"
@@ -351,6 +363,9 @@
     pretty BuiltinFloor   = "floor"
     pretty BuiltinCeil    = "ceil"
     pretty BuiltinMatch   = "match"
+    pretty BuiltinSome    = "Some"
+    pretty BuiltinNone    = "None"
+    pretty BuiltinFp      = "fp"
 
 data Token a = EOF { loc :: a }
              | TokSym { loc :: a, _sym :: Sym }
diff --git a/src/Jacinda/Parser.y b/src/Jacinda/Parser.y
--- a/src/Jacinda/Parser.y
+++ b/src/Jacinda/Parser.y
@@ -52,6 +52,8 @@
     backslashdot { TokSym $$ BackslashDot }
     at { $$@(TokAccess _ _) }
     select { $$@(TokSelect _ _) }
+    floorSym { TokSym $$ FloorSym }
+    ceilSym { TokSym $$ CeilSym }
 
     plus { TokSym $$ PlusTok }
     minus { TokSym $$ MinusTok }
@@ -108,6 +110,9 @@
     ceil { TokBuiltin $$ BuiltinCeil }
     option { TokBuiltin $$ BuiltinOption }
     match { TokBuiltin $$ BuiltinMatch }
+    some { TokBuiltin $$ BuiltinSome }
+    none { TokBuiltin $$ BuiltinNone }
+    fp { TokBuiltin $$ BuiltinFp }
 
     iParse { TokBuiltin $$ BuiltinIParse }
     fParse { TokBuiltin $$ BuiltinFParse }
@@ -186,6 +191,10 @@
   | field fParse { EApp (loc $1) (UBuiltin $2 FParse) (Field (loc $1) (ix $1)) }
   | name iParse { EApp (Name.loc $1) (UBuiltin $2 IParse) (Var (Name.loc $1) $1) }
   | name fParse { EApp (Name.loc $1) (UBuiltin $2 FParse) (Var (Name.loc $1) $1) }
+  | field colon { EApp (loc $1) (UBuiltin $2 Parse) (Field (loc $1) (ix $1)) }
+  | name colon { EApp (Name.loc $1) (UBuiltin $2 Parse) (Var (Name.loc $1) $1) }
+  | x colon { EApp $1 (UBuiltin $2 Parse) (ResVar $1 X) }
+  | y colon { EApp $1 (UBuiltin $2 Parse) (ResVar $1 Y) }
   | x iParse { EApp $1 (UBuiltin $2 IParse) (ResVar $1 X) }
   | x fParse { EApp $1 (UBuiltin $2 FParse) (ResVar $1 X) }
   | y iParse { EApp $1 (UBuiltin $2 IParse) (ResVar $1 Y) }
@@ -222,7 +231,12 @@
   | option { TBuiltin $1 Option }
   | floor { UBuiltin $1 Floor }
   | ceil { UBuiltin $1 Ceiling }
+  | floorSym { UBuiltin $1 Floor }
+  | ceilSym { UBuiltin $1 Ceiling }
+  | some { UBuiltin $1 Some }
   | ix { NBuiltin $1 Ix }
+  | none { NBuiltin $1 None }
+  | fp { NBuiltin $1 Fp }
   | parens(at) { UBuiltin (loc $1) (At $ ix $1) }
   | parens(select) { UBuiltin (loc $1) (Select $ field $1) }
   | E at { EApp (eLoc $1) (UBuiltin (loc $2) (At $ ix $2)) $1 }
diff --git a/src/Jacinda/Parser/Rewrite.hs b/src/Jacinda/Parser/Rewrite.hs
--- a/src/Jacinda/Parser/Rewrite.hs
+++ b/src/Jacinda/Parser/Rewrite.hs
@@ -31,6 +31,7 @@
     a (EAppF l e0@(EApp _ (BBuiltin _ Matches) _) (EApp l1 (EApp l2 e1@(BBuiltin _ Or) e2) e3))     = EApp l1 (EApp l2 e1 (EApp l e0 e2)) e3
     a (EAppF l e0@(EApp _ (BBuiltin _ NotMatches) _) (EApp l1 (EApp l2 e1@(BBuiltin _ And) e2) e3)) = EApp l1 (EApp l2 e1 (EApp l e0 e2)) e3
     a (EAppF l e0@(EApp _ (BBuiltin _ NotMatches) _) (EApp l1 (EApp l2 e1@(BBuiltin _ Or) e2) e3))  = EApp l1 (EApp l2 e1 (EApp l e0 e2)) e3
+    -- TODO rewrite dfn
     a (EAppF l e0@Var{} (EApp lϵ e1 e2))                                                            = EApp l (EApp lϵ e0 e1) e2
     a (EAppF l e0@(BBuiltin _ Max) (EApp lϵ e1 e2))                                                 = EApp l (EApp lϵ e0 e1) e2
     a (EAppF l e0@(BBuiltin _ Min) (EApp lϵ e1 e2))                                                 = EApp l (EApp lϵ e0 e1) e2
diff --git a/src/Jacinda/Ty.hs b/src/Jacinda/Ty.hs
--- a/src/Jacinda/Ty.hs
+++ b/src/Jacinda/Ty.hs
@@ -20,7 +20,8 @@
 import qualified Data.Set                   as S
 import qualified Data.Text                  as T
 import           Data.Typeable              (Typeable)
-import           Debug.Trace
+import qualified Data.Vector                as V
+import qualified Data.Vector.Ext            as V
 import           Intern.Name
 import           Intern.Unique
 import           Jacinda.AST
@@ -37,11 +38,13 @@
 data Error a = UnificationFailed a (T ()) (T ())
              | Doesn'tSatisfy a (T ()) C
              | IllScoped a (Name a)
+             | Ambiguous (E ())
 
 instance Pretty a => Pretty (Error a) where
     pretty (UnificationFailed l ty ty') = pretty l <+> "could not unify type" <+> squotes (pretty ty) <+> "with" <+> squotes (pretty ty')
     pretty (Doesn'tSatisfy l ty c)      = pretty l <+> squotes (pretty ty) <+> "is not a member of class" <+> pretty c
     pretty (IllScoped l n)              = pretty l <+> squotes (pretty n) <+> "is not in scope."
+    pretty (Ambiguous e)                = "type of" <+> squotes (pretty e) <+> "is ambiguous"
 
 instance Pretty a => Show (Error a) where
     show = show . pretty
@@ -150,6 +153,7 @@
 
 substConstraints :: IM.IntMap (T a) -> T a -> T a
 substConstraints _ ty@TyB{}                             = ty
+substConstraints _ ty@TyNamed{}                         = ty
 substConstraints tys ty@(TyVar _ (Name _ (Unique k) _)) = fromMaybe ty (substInt tys k)
 substConstraints tys (TyTup l tysϵ)                     = TyTup l (substConstraints tys <$> tysϵ)
 substConstraints tys (TyApp l ty ty')                   =
@@ -197,6 +201,7 @@
 checkType (TyB _ TyInteger) (IsEq, _)          = pure ()
 checkType (TyB _ TyInteger) (IsParseable, _)   = pure ()
 checkType (TyB _ TyFloat) (IsParseable, _)     = pure ()
+checkType ty (IsParseable, l)                  = throwError $ Doesn'tSatisfy l (void ty) IsParseable
 checkType (TyB _ TyFloat) (IsSemigroup, _)     = pure ()
 checkType (TyB _ TyFloat) (IsNum, _)           = pure ()
 checkType (TyB _ TyFloat) (IsOrd, _)           = pure ()
@@ -261,6 +266,28 @@
     pure $ FunDecl (n $> ty) [] e'
 tyD0 FunDecl{} = error "Internal error. Should have been desugared by now."
 
+isAmbiguous :: T K -> Bool
+isAmbiguous TyVar{}          = True
+isAmbiguous (TyArr _ ty ty') = isAmbiguous ty || isAmbiguous ty'
+isAmbiguous (TyApp _ ty ty') = isAmbiguous ty || isAmbiguous ty'
+isAmbiguous (TyTup _ tys)    = any isAmbiguous tys
+isAmbiguous TyNamed{}        = False
+isAmbiguous TyB{}            = False
+
+checkAmb :: E (T K) -> TypeM a ()
+checkAmb e@(BBuiltin ty _) | isAmbiguous ty = throwError $ Ambiguous (void e)
+checkAmb TBuiltin{} = pure () -- don't fail on ternary builtins, we don't need it anyway... better error messages
+checkAmb e@(UBuiltin ty _) | isAmbiguous ty = throwError $ Ambiguous (void e)
+checkAmb (Implicit _ e') = checkAmb e'
+checkAmb (Guarded _ p e') = checkAmb p *> checkAmb e'
+checkAmb (EApp _ e' e'') = checkAmb e' *> checkAmb e'' -- more precise errors, don't fail yet! (if they aren't ambiguous, it shouldn't be
+checkAmb (Tup _ es) = traverse_ checkAmb es
+checkAmb e@(Arr ty _) | isAmbiguous ty = throwError $ Ambiguous (void e)
+checkAmb e@(Var ty _) | isAmbiguous ty = throwError $ Ambiguous (void e)
+checkAmb (Let _ bs e) = traverse_ checkAmb [e, snd bs]
+checkAmb (Lam _ _ e) = checkAmb e -- I think
+checkAmb _ = pure ()
+
 tyProgram :: Ord a => Program a -> TypeM a (Program (T K))
 tyProgram (Program ds e) = do
     ds' <- traverse tyD0 ds
@@ -270,7 +297,8 @@
     traverse_ (uncurry (checkClass backNames)) toCheck
     backNames' <- unifyM =<< gets constraints
     -- FIXME: not sure if termination/whatever is guaranteed, need 2 think..
-    pure (fmap (substConstraints backNames') (Program ds' e'))
+    let res = fmap (substConstraints backNames') (Program ds' e')
+    checkAmb (expr res) $> res
 
 -- FIXME kind check
 tyE :: Ord a => E a -> TypeM a (E (T K))
@@ -326,6 +354,9 @@
 tyVec :: T K
 tyVec = TyB (KArr Star Star) TyVec
 
+mkVec :: T K -> T K
+mkVec = hkt tyVec
+
 tyOpt :: T K -> T K
 tyOpt = hkt (TyB (KArr Star Star) TyOption)
 
@@ -342,6 +373,7 @@
 tyE0 AllField{}              = pure $ AllField tyStr
 tyE0 AllColumn{}             = pure $ AllColumn (tyStream tyStr)
 tyE0 (NBuiltin _ Ix)         = pure $ NBuiltin tyI Ix
+tyE0 (NBuiltin _ Fp)         = pure $ NBuiltin tyStr Fp
 tyE0 (BBuiltin l Plus)       = BBuiltin <$> tySemiOp l <*> pure Plus
 tyE0 (BBuiltin l Minus)      = BBuiltin <$> tyNumOp l <*> pure Minus
 tyE0 (BBuiltin l Times)      = BBuiltin <$> tyNumOp l <*> pure Times
@@ -353,8 +385,8 @@
 tyE0 (BBuiltin l Neq)        = BBuiltin <$> tyEq l <*> pure Neq
 tyE0 (BBuiltin l Min)        = BBuiltin <$> tyM l <*> pure Min
 tyE0 (BBuiltin l Max)        = BBuiltin <$> tyM l <*> pure Max
-tyE0 (BBuiltin _ Split)      = pure $ BBuiltin (tyArr tyStr (tyArr tyStr (hkt tyVec tyStr))) Split
-tyE0 (BBuiltin _ Splitc)     = pure $ BBuiltin (tyArr tyStr (tyArr tyStr (hkt tyVec tyStr))) Splitc
+tyE0 (BBuiltin _ Split)      = pure $ BBuiltin (tyArr tyStr (tyArr tyStr (mkVec tyStr))) Split
+tyE0 (BBuiltin _ Splitc)     = pure $ BBuiltin (tyArr tyStr (tyArr tyStr (mkVec tyStr))) Splitc
 tyE0 (BBuiltin _ Matches)    = pure $ BBuiltin (tyArr tyStr (tyArr tyStr tyBool)) Matches
 tyE0 (BBuiltin _ NotMatches) = pure $ BBuiltin (tyArr tyStr (tyArr tyStr tyBool)) NotMatches
 tyE0 (UBuiltin _ Tally)      = pure $ UBuiltin (tyArr tyStr tyI) Tally
@@ -368,6 +400,18 @@
 tyE0 (UBuiltin _ FParse)     = pure $ UBuiltin (tyArr tyStr tyF) FParse
 tyE0 (UBuiltin _ Floor)      = pure $ UBuiltin (tyArr tyF tyI) Floor
 tyE0 (UBuiltin _ Ceiling)    = pure $ UBuiltin (tyArr tyF tyI) Ceiling
+tyE0 (UBuiltin _ Some) = do
+    a <- dummyName "a"
+    let a' = var a
+    pure $ UBuiltin (tyArr a' (tyOpt a')) Some
+tyE0 (NBuiltin _ None) = do
+    a <- dummyName "a"
+    pure $ NBuiltin (tyOpt $ var a) None
+tyE0 (UBuiltin l Parse) = do
+    a <- dummyName "a"
+    let a' = var a
+    modifying classVarsLens (addC a (IsParseable, l))
+    pure $ UBuiltin (tyArr tyStr a') Parse
 tyE0 (BBuiltin l Sprintf) = do
     a <- dummyName "a"
     let a' = var a
@@ -499,3 +543,12 @@
     a <- dummyName "a"
     let a' = var a
     pure $ OptionVal (tyOpt a') Nothing
+tyE0 (Arr l v) | V.null v = do
+    a <- dummyName "a"
+    let a' = var a
+    pure $ Arr (mkVec a') V.empty
+               | otherwise = do
+    v' <- traverse tyE0 v
+    let x = V.head v'
+    V.priorM_ (\y y' -> pushConstraint l (eLoc y) (eLoc y')) v'
+    pure $ Arr (eLoc x) v'
