diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,30 +1,29 @@
-Copyright Joe Vargas (c) 2016
+BSD 3-Clause License
 
+Copyright (c) 2017, Joe Vargas
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
 
-    * Redistributions in binary form must reproduce the above
-      copyright notice, this list of conditions and the following
-      disclaimer in the documentation and/or other materials provided
-      with the distribution.
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
 
-    * Neither the name of Joe Vargas nor the names of other
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
+* Neither the name of the copyright holder nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,1 @@
+# colorless-haskell
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,2 +0,0 @@
-import Distribution.Simple
-main = defaultMain
diff --git a/colorless.cabal b/colorless.cabal
--- a/colorless.cabal
+++ b/colorless.cabal
@@ -1,60 +1,70 @@
-name:
-  colorless
-version:
-  0.0.0
-synopsis:
-  Yet another IDL for RPC
-description:
-  Please see README.md
-homepage:
-  http://github.com/jxv/colorless#readme
-license:
-  BSD3
-license-file:
-  LICENSE
-author:
-  Joe Vargas
-maintainer:
-  http://github.com/jxv
-copyright:
-  2016 Joe Vargas
-category:
-  Web
-build-type:
-  Simple
--- extra-source-files:
-cabal-version:
-  >=1.10
+-- This file has been generated from package.yaml by hpack version 0.17.0.
+--
+-- see: https://github.com/sol/hpack
 
+name:           colorless
+version:        0.0.1
+synopsis:       Colorless
+description:    Colorless
+category:       Web
+maintainer:     Joe Vargas
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+extra-source-files:
+    package.yaml
+    README.md
+
 library
   hs-source-dirs:
-    src
-  exposed-modules:
-    Colorless.CodeGen.Types
+      library
+  default-extensions: ConstraintKinds DeriveGeneric DuplicateRecordFields FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving KindSignatures LambdaCase MultiParamTypeClasses NamedFieldPuns OverloadedStrings RankNTypes ScopedTypeVariables TupleSections TypeApplications TypeOperators
+  ghc-options: -Wall
   build-depends:
-      base >= 4.7 && < 5
-    , pregame == 1.0.3.0
-    , megaparsec
-  default-language:
-    Haskell2010
-  default-extensions:
-    NoImplicitPrelude
-    OverloadedStrings
-    TypeSynonymInstances
-    FlexibleInstances
-    FlexibleContexts
-    GeneralizedNewtypeDeriving
-    LambdaCase
-    ScopedTypeVariables
-    NamedFieldPuns
-    MultiParamTypeClasses
-    TypeFamilies
-    TupleSections
-    DuplicateRecordFields
-    OverloadedLists
+      aeson
+    , base >= 4.7 && < 5
+    , bytestring
+    , containers
+    , errors
+    , exceptions
+    , lifted-async
+    , monad-control
+    , monad-logger
+    , mtl
+    , random
+    , scientific
+    , text
+    , unordered-containers
+    , vector
+  exposed-modules:
+      Colorless.Endpoint
+      Colorless.Runtime.Ast
+      Colorless.Runtime.Expr
+      Colorless.Runtime.Types
+      Colorless.Runtime.Val
+      Colorless.Types
+  default-language: Haskell2010
 
-source-repository head
-  type:
-    git
-  location:
-    https://github.com/jxv/colorless
+test-suite colorless-suite
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  hs-source-dirs:
+      tests
+  default-extensions: ConstraintKinds DeriveGeneric DuplicateRecordFields FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving KindSignatures LambdaCase MultiParamTypeClasses NamedFieldPuns OverloadedStrings RankNTypes ScopedTypeVariables TupleSections TypeApplications TypeOperators
+  ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N
+  build-depends:
+      aeson
+    , base >= 4.7 && < 5
+    , colorless
+    , containers
+    , hspec
+    , scientific
+    , text
+    , vector
+  other-modules:
+      AstSpec
+      ExprSpec
+      ValSpec
+  default-language: Haskell2010
diff --git a/library/Colorless/Endpoint.hs b/library/Colorless/Endpoint.hs
new file mode 100644
--- /dev/null
+++ b/library/Colorless/Endpoint.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE DataKinds #-}
+module Colorless.Endpoint
+  ( runColorless
+  , runColorlessSingleton
+  ) where
+
+import qualified Data.Map as Map
+import qualified Data.HashMap.Lazy as HML
+import Control.Monad.IO.Class (MonadIO(..))
+import Control.Concurrent.Async.Lifted ()
+import Data.Aeson
+import Data.Aeson.Types (parseMaybe)
+import Data.Text (Text)
+import Data.Map (Map)
+
+import Colorless.Types
+
+runColorlessSingleton
+  :: (MonadIO m, RuntimeThrower m)
+  => Version
+  -> (Request -> m Response)
+  -> Value
+  -> m Value
+runColorlessSingleton Version{major,minor} handleRequest = runColorless (Map.singleton major (minor, handleRequest))
+
+runColorless
+  :: (MonadIO m, RuntimeThrower m)
+  => Map Major (Minor, Request -> m Response)
+  -> Value
+  -> m Value
+runColorless handleRequestMap v = do
+  colorlessVersion <- getColorlessVersion v
+  assertColorlessVersionCompatiability colorlessVersion
+  apiVersion <- getApiVersion v
+  let apiMajor = major apiVersion
+  case Map.lookup apiMajor handleRequestMap of
+    Nothing -> case leastAndGreatest (Map.keys handleRequestMap) of
+      Nothing -> runtimeThrow RuntimeError'NoImplementation
+      Just (minMajor, maxMajor) ->
+        if minMajor > apiMajor
+          then runtimeThrow RuntimeError'ApiMajorVersionTooLow
+          else if maxMajor < apiMajor
+            then runtimeThrow RuntimeError'ApiMajorVersionTooHigh
+            else runtimeThrow RuntimeError'NoImplementation
+    Just (maxMinor, handleRequest) -> if minor apiVersion > maxMinor
+      then runtimeThrow RuntimeError'ApiMinorVersionTooHigh
+      else case parseRequest v of
+        Nothing -> runtimeThrow RuntimeError'UnparsableFormat
+        Just req -> toJSON <$> handleRequest req
+
+leastAndGreatest :: Ord a => [a] -> Maybe (a,a)
+leastAndGreatest [] = Nothing
+leastAndGreatest xs = Just (minimum xs, maximum xs)
+
+assertColorlessVersionCompatiability :: RuntimeThrower m => Version -> m ()
+assertColorlessVersionCompatiability Version{major,minor}
+  | major > mustMajor = runtimeThrow RuntimeError'ColorlessMajorVersionTooHigh
+  | major < mustMajor = runtimeThrow RuntimeError'ColorlessMajorVersionTooLow
+  | minor > maxMinor = runtimeThrow RuntimeError'ColorlessMinorVersionTooHigh
+  | otherwise = return ()
+  where
+    mustMajor = 0
+    maxMinor = 0
+
+getApiVersion :: RuntimeThrower m => Value -> m Version
+getApiVersion = getVersion "version" RuntimeError'NoApiVersion
+
+getColorlessVersion :: RuntimeThrower m => Value -> m Version
+getColorlessVersion = getVersion "colorless" RuntimeError'NoColorlessVersion
+
+getVersion :: RuntimeThrower m => Text -> RuntimeError -> Value -> m Version
+getVersion name err (Object o) = case HML.lookup name o of
+  Just x -> maybe (runtimeThrow err) return (parseMaybe parseJSON x)
+  Nothing -> runtimeThrow err
+getVersion _ err _ = runtimeThrow err
+
+parseRequest :: Value -> Maybe Request
+parseRequest = parseMaybe parseJSON
diff --git a/library/Colorless/Runtime/Ast.hs b/library/Colorless/Runtime/Ast.hs
new file mode 100644
--- /dev/null
+++ b/library/Colorless/Runtime/Ast.hs
@@ -0,0 +1,226 @@
+{-# LANGUAGE DeriveGeneric #-}
+module Colorless.Runtime.Ast
+  ( Ast(..)
+  , Ref(..)
+  , If(..)
+  , Set(..)
+  , Get(..)
+  , Define(..)
+  , Lambda(..)
+  , List(..)
+  , Begin(..)
+  , FnCall(..)
+  , Enumerator(..)
+  , Struct(..)
+  , Wrap(..)
+  , StructCall(..)
+  , WrapCall(..)
+  , EnumerationCall(..)
+  , HollowCall(..)
+  , Const(..)
+  ) where
+
+import qualified Data.HashMap.Lazy as HML
+import qualified Data.Vector as V
+import Control.Monad (mzero)
+import Control.Applicative ((<|>))
+import Data.Text (Text)
+import Data.Aeson
+import Data.Map (Map)
+import GHC.Generics (Generic)
+
+import Colorless.Runtime.Types
+
+data Ast
+  = Ast'Ref Ref
+  | Ast'If If
+  | Ast'Set Set
+  | Ast'Get Get
+  | Ast'Define Define
+  | Ast'Lambda Lambda
+  | Ast'List List
+  | Ast'Begin Begin
+  | Ast'FnCall FnCall
+  | Ast'WrapCall WrapCall
+  | Ast'StructCall StructCall
+  | Ast'EnumerationCall EnumerationCall
+  | Ast'HollowCall HollowCall
+  | Ast'Enumerator Enumerator
+  | Ast'Struct Struct
+  | Ast'Wrap Wrap
+  | Ast'Const Const
+  deriving (Show, Eq)
+
+instance FromJSON Ast where
+  parseJSON v
+    =   (Ast'Ref <$> parseJSON v)
+    <|> (Ast'If <$> parseJSON v)
+    <|> (Ast'Set <$> parseJSON v)
+    <|> (Ast'Get <$> parseJSON v)
+    <|> (Ast'Define <$> parseJSON v)
+    <|> (Ast'Lambda <$> parseJSON v)
+    <|> (Ast'List <$> parseJSON v)
+    <|> (Ast'Begin <$> parseJSON v)
+    <|> (Ast'FnCall <$> parseJSON v)
+    <|> (Ast'EnumerationCall <$> parseJSON v)
+    <|> (Ast'WrapCall <$> parseJSON v)
+    <|> (Ast'StructCall <$> parseJSON v)
+    <|> (Ast'HollowCall <$> parseJSON v)
+    <|> (Ast'Enumerator <$> parseJSON v)
+    <|> (Ast'Struct <$> parseJSON v)
+    <|> (Ast'Wrap <$> parseJSON v)
+    <|> (Ast'Const <$> parseJSON v)
+
+data Ref = Ref
+  { symbol :: Symbol
+  } deriving (Show, Eq)
+
+instance FromJSON Ref where
+  parseJSON (Object o) = Ref <$> o .: "@"
+  parseJSON _ = mzero
+
+data If = If
+  { cond :: Ast
+  , true :: Ast
+  , false :: Ast
+  } deriving (Show, Eq)
+
+instance FromJSON If where
+  parseJSON (Array arr) = case V.toList arr of
+    ["if", cond, true, false] -> If <$> parseJSON cond <*> parseJSON true <*> parseJSON false
+    _ -> mzero
+  parseJSON _ = mzero
+
+data Set = Set
+  { var :: Symbol
+  , expr :: Ast
+  } deriving (Show, Eq)
+
+instance FromJSON Set where
+  parseJSON (Array arr) = case V.toList arr of
+    ["set", var, expr] -> Set <$> parseJSON var <*> parseJSON expr
+    _ -> mzero
+  parseJSON _ = mzero
+
+data Get = Get
+  { path :: [Text]
+  , val :: Ast
+  } deriving (Show, Eq)
+
+instance FromJSON Get where
+  parseJSON (Array arr) = case V.toList arr of
+    ["get", path, val] -> Get <$> parseJSON path <*> parseJSON val
+    _ -> mzero
+  parseJSON _ = mzero
+
+data Define = Define
+  { var :: Symbol
+  , expr :: Ast
+  } deriving (Show, Eq)
+
+instance FromJSON Define where
+  parseJSON (Array arr) = case V.toList arr of
+    ["def", var, expr] -> Define <$> parseJSON var <*> parseJSON expr
+    _ -> mzero
+  parseJSON _ = mzero
+
+data Lambda = Lambda
+  { args :: [(Symbol, Type)]
+  , expr :: Ast
+  } deriving (Show, Eq)
+
+instance FromJSON Lambda where
+  parseJSON (Array arr) = case V.toList arr of
+    ["fn", Array params, expr] -> Lambda <$> mapM parseParam (V.toList params) <*> parseJSON expr
+    _ -> mzero
+    where
+      parseParam = \case
+        Object o -> case HML.toList o of
+          [(key,val)] -> (Symbol key,) <$> parseJSON val
+          _ -> mzero
+        _ -> mzero
+  parseJSON _ = mzero
+
+data List = List
+  { list :: [Ast]
+  } deriving (Show, Eq)
+
+instance FromJSON List where
+  parseJSON (Object o) = List <$> o .: "List"
+  parseJSON _ = mzero
+
+data Begin = Begin
+  { vals :: [Ast]
+  } deriving (Show, Eq)
+
+instance FromJSON Begin where
+  parseJSON (Array arr) = case V.toList arr of
+    "begin":xs -> Begin <$> mapM parseJSON xs
+    _ -> mzero
+  parseJSON _ = mzero
+
+data FnCall = FnCall
+  { fn :: Ast
+  , args :: [Ast]
+  } deriving (Show, Eq)
+
+instance FromJSON FnCall where
+  parseJSON (Array arr) = case V.toList arr of
+    ((String x):xs) -> FnCall <$> pure (Ast'Ref $ Ref $ Symbol x) <*> mapM parseJSON xs
+    (x:xs) -> FnCall <$> parseJSON x <*> mapM parseJSON xs
+    _ -> mzero
+  parseJSON _ = mzero
+
+data EnumerationCall = EnumerationCall
+  { n :: TypeName
+  , e :: Ast
+  } deriving (Show, Eq, Generic)
+
+instance FromJSON EnumerationCall
+
+data WrapCall = WrapCall
+  { n :: TypeName
+  , w :: Ast
+  } deriving (Show, Eq, Generic)
+
+instance FromJSON WrapCall
+
+data StructCall = StructCall
+  { n :: TypeName
+  , m :: Map MemberName Ast
+  } deriving (Show, Eq, Generic)
+
+instance FromJSON StructCall
+
+data HollowCall = HollowCall
+  { n :: TypeName
+  } deriving (Show, Eq, Generic)
+
+instance FromJSON HollowCall
+
+data Enumerator = Enumerator
+  { tag :: EnumeratorName
+  , m :: Maybe (Map MemberName Ast)
+  } deriving (Show, Eq, Generic)
+
+instance FromJSON Enumerator where
+  parseJSON (Object o) = do
+    tag <- o .: "tag"
+    let tagless = HML.delete "tag" o
+    if HML.size o == 1
+      then pure $ Enumerator tag Nothing
+      else Enumerator tag <$> (Just <$> parseJSON (Object tagless))
+  parseJSON _ = mzero
+
+data Struct = Struct
+  { m :: Map MemberName Ast
+  } deriving (Show, Eq, Generic)
+
+instance FromJSON Struct where
+  parseJSON v = Struct <$> parseJSON v
+
+data Wrap = Wrap
+  { w :: Ast
+  } deriving (Show, Eq, Generic)
+
+instance FromJSON Wrap
diff --git a/library/Colorless/Runtime/Expr.hs b/library/Colorless/Runtime/Expr.hs
new file mode 100644
--- /dev/null
+++ b/library/Colorless/Runtime/Expr.hs
@@ -0,0 +1,677 @@
+{-# LANGUAGE RankNTypes #-}
+module Colorless.Runtime.Expr
+  ( Expr(..)
+  , EvalConfig(..)
+  --
+  , Ref(..)
+  , UnVal(..)
+  , UnEnumerator(..)
+  , UnWrap(..)
+  , UnStruct(..)
+  , If(..)
+  , Set(..)
+  , Get(..)
+  , Define(..)
+  , Lambda(..)
+  , Fn(..)
+  , List(..)
+  , Begin(..)
+  , FnCall(..)
+  , ApiUnCall(..)
+  , HollowUnCall(..)
+  , WrapUnCall(..)
+  , StructUnCall(..)
+  , EnumerationUnCall(..)
+  , Val(..)
+  , ApiVal(..)
+  , Wrap(..)
+  , Struct(..)
+  , Enumerator(..)
+  , ApiCall(..)
+  --
+  , jsonToExpr
+  , apiCallName
+  , fromAst
+  --
+  , ApiParser(..)
+  , parseApiCall
+  --
+  , eval
+  , forceVal
+  , runEval
+  , emptyEnv
+  ) where
+
+import qualified Data.Map as Map
+import Control.Monad (when, join)
+import Control.Monad.IO.Class (MonadIO(..))
+import Control.Monad.Reader (MonadReader(..), ReaderT(..), asks, lift)
+import Data.Map (Map)
+import Data.Int
+import Data.Word
+import Data.Aeson (parseJSON, Value)
+import Data.Aeson.Types (parseMaybe)
+import Data.IORef (IORef, readIORef, newIORef, writeIORef)
+import Data.Scientific (toBoundedInteger, Scientific)
+import Data.Text (Text)
+
+import qualified Colorless.Runtime.Ast as Ast
+import Colorless.Types
+import Colorless.Runtime.Types
+import Colorless.Runtime.Val
+import Colorless.Runtime.Ast (Ast(..))
+
+data EvalConfig m = EvalConfig
+  { options :: Options
+  , apiCall :: ApiCall -> m Val
+  }
+
+jsonToExpr :: (Monad m) => Value -> Maybe (Expr m)
+jsonToExpr = fmap fromAst . parseMaybe parseJSON
+
+newtype Eval m a = Eval (ReaderT (EvalConfig m) m a)
+  deriving (Functor, Applicative, Monad, MonadReader (EvalConfig m), MonadIO)
+
+instance RuntimeThrower m => RuntimeThrower (Eval m) where
+  runtimeThrow err = Eval (lift $ runtimeThrow err)
+
+getOptions :: Monad m => Eval m Options
+getOptions = asks options
+
+type Env m = Map Symbol (IORef (Expr m))
+
+runEval :: MonadIO m => Eval m a -> EvalConfig m -> m a
+runEval (Eval r) = runReaderT r
+
+data Expr m
+  = Expr'Ref Ref
+  | Expr'UnVal (UnVal m)
+  | Expr'Val Val
+  | Expr'If (If m)
+  | Expr'Set (Set m)
+  | Expr'Get (Get m)
+  | Expr'Define (Define m)
+  | Expr'Lambda (Lambda m)
+  | Expr'List (List m)
+  | Expr'Fn (Fn m)
+  | Expr'FnCall (FnCall m)
+  | Expr'Begin (Begin m)
+  | Expr'ApiUnCall (ApiUnCall m)
+  deriving (Show, Eq)
+
+data UnVal m
+  = UnVal'Const Const
+  | UnVal'UnWrap (UnWrap m)
+  | UnVal'UnStruct (UnStruct m)
+  | UnVal'UnEnumerator (UnEnumerator m)
+  deriving (Show, Eq)
+
+data UnWrap m = UnWrap
+  { w :: Expr m
+  } deriving (Show, Eq)
+
+data UnStruct m = UnStruct
+  { m :: Map MemberName (Expr m)
+  } deriving (Show, Eq)
+
+data UnEnumerator m = UnEnumerator
+  { tag :: EnumeratorName
+  , m :: Maybe (Map MemberName (Expr m))
+  } deriving (Show, Eq)
+
+data Ref = Ref
+  { symbol :: Symbol
+  } deriving (Show, Eq)
+
+data If m = If
+  { cond :: Expr m
+  , true :: Expr m
+  , false :: Expr m
+  } deriving (Show, Eq)
+
+data Set m = Set
+  { var :: Symbol
+  , expr :: Expr m
+  } deriving (Show, Eq)
+
+data Get m = Get
+  { path :: [Text]
+  , expr :: Expr m
+  } deriving (Show, Eq)
+
+data Define m = Define
+  { var :: Symbol
+  , expr :: Expr m
+  } deriving (Show, Eq)
+
+data Lambda m = Lambda
+  { params :: [(Symbol, Type)]
+  , expr :: Expr m
+  } deriving (Show, Eq)
+
+newtype Fn m = Fn ([Expr m] -> Eval m (Expr m))
+
+instance Show (Fn m) where
+  show _ = "<Fn>"
+
+instance Eq (Fn m) where
+  (==) _ _ = False
+
+data List m = List
+  { list :: [Expr m]
+  } deriving (Show, Eq)
+
+data Begin m = Begin
+  { exprs :: [Expr m]
+  } deriving (Show, Eq)
+
+data FnCall m = FnCall
+  { fn :: Expr m
+  , args :: [Expr m]
+  } deriving (Show, Eq)
+
+data ApiUnCall m
+  = ApiUnCall'HollowUnCall HollowUnCall
+  | ApiUnCall'WrapUnCall (WrapUnCall m)
+  | ApiUnCall'StructUnCall (StructUnCall m)
+  | ApiUnCall'EnumerationUnCall (EnumerationUnCall m)
+  deriving (Show, Eq)
+
+data HollowUnCall = HollowUnCall
+  { n :: TypeName
+  } deriving (Show, Eq)
+
+data WrapUnCall m = WrapUnCall
+  { n :: TypeName
+  , w :: Expr m
+  } deriving (Show, Eq)
+
+data StructUnCall m = StructUnCall
+  { n :: TypeName
+  , m :: Map MemberName (Expr m)
+  } deriving (Show, Eq)
+
+data EnumerationUnCall m = EnumerationUnCall
+  { n :: TypeName
+  , e :: Expr m
+  } deriving (Show, Eq)
+
+data ApiCall
+  = ApiCall'Hollow TypeName
+  | ApiCall'Struct TypeName Struct
+  | ApiCall'Enumeration TypeName Enumerator
+  | ApiCall'Wrap TypeName Wrap
+  deriving (Show, Eq)
+
+apiCallName :: ApiCall -> TypeName
+apiCallName = \case
+  ApiCall'Hollow n -> n
+  ApiCall'Struct n _ -> n
+  ApiCall'Enumeration n _ -> n
+  ApiCall'Wrap n _ -> n
+
+--
+
+fromAst :: Monad m => Ast -> Expr m
+fromAst = \case
+  Ast'Ref Ast.Ref{symbol} -> Expr'Ref $ Ref symbol
+  Ast'If Ast.If{cond,true,false} -> Expr'If $ If (fromAst cond) (fromAst true) (fromAst false)
+  Ast'Set Ast.Set{var,expr} -> Expr'Set $ Set var (fromAst expr)
+  Ast'Get Ast.Get{path,val} -> Expr'Get $ Get path (fromAst val)
+  Ast'Define Ast.Define{var,expr} -> Expr'Define $ Define var (fromAst expr)
+  Ast'Lambda Ast.Lambda{args,expr} -> Expr'Lambda $ Lambda args (fromAst expr)
+  Ast'List Ast.List{list} -> Expr'List $ List $ map fromAst list
+  Ast'Begin Ast.Begin{vals} -> Expr'Begin $ Begin $ map fromAst vals
+  Ast'FnCall Ast.FnCall{fn,args} -> Expr'FnCall $ FnCall (fromAst fn) (map fromAst args)
+  Ast'WrapCall Ast.WrapCall{n,w} -> Expr'ApiUnCall $ ApiUnCall'WrapUnCall $ WrapUnCall n (fromAst w)
+  Ast'HollowCall Ast.HollowCall{n} -> Expr'ApiUnCall $ ApiUnCall'HollowUnCall $ HollowUnCall n
+  Ast'StructCall Ast.StructCall{n,m} -> Expr'ApiUnCall $ ApiUnCall'StructUnCall $ StructUnCall n (fromAst <$> m)
+  Ast'EnumerationCall Ast.EnumerationCall{n,e} -> Expr'ApiUnCall $ ApiUnCall'EnumerationUnCall $ EnumerationUnCall n (fromAst e)
+  Ast'Enumerator Ast.Enumerator{tag,m} -> Expr'UnVal $ UnVal'UnEnumerator $ UnEnumerator tag (fmap fromAst <$> m)
+  Ast'Struct Ast.Struct{m} -> Expr'UnVal $ UnVal'UnStruct $ UnStruct (fromAst <$> m)
+  Ast'Wrap Ast.Wrap{w} -> Expr'UnVal $ UnVal'UnWrap $ UnWrap (fromAst w)
+  Ast'Const c -> Expr'UnVal $ UnVal'Const c
+
+--
+
+addEnvToEnv :: (RuntimeThrower m, Ord k, MonadIO m) => Maybe Int -> Map k a -> IORef (Map k a) -> m (IORef (Map k a))
+addEnvToEnv maybeVariableLimit vars envRef = do
+  env <- liftIO $ readIORef envRef
+  let env' = Map.union vars env
+  case maybeVariableLimit of
+    Nothing -> return ()
+    Just limit -> when (Map.size env' > limit) $ runtimeThrow RuntimeError'VariableLimit
+  liftIO $ newIORef env'
+
+addVarToEnv :: (Ord k, MonadIO m, RuntimeThrower m) => Maybe Int -> IORef (Map k a) -> k -> a -> Map k a -> m ()
+addVarToEnv maybeVariableLimit envRef var ref env = do
+  let env' = Map.insert var ref env
+  case maybeVariableLimit of
+    Nothing -> return ()
+    Just limit -> when (Map.size env' > limit) $ runtimeThrow RuntimeError'VariableLimit
+  liftIO $ writeIORef envRef env'
+
+varLookup :: (MonadIO m, RuntimeThrower m) => Map Symbol (IORef a) -> Symbol -> m a
+varLookup env symbol@(Symbol s) = case Map.lookup symbol env of
+  Nothing -> runtimeThrow $ RuntimeError'UnknownVariable s
+  Just var -> liftIO $ readIORef $ var
+
+--
+
+eval :: (MonadIO m, RuntimeThrower m) => Expr m -> IORef (Env m) -> Eval m (Expr m)
+eval expr envRef = case expr of
+  Expr'Ref atom -> evalRef atom envRef
+  Expr'If if' -> evalIf if' envRef
+  Expr'UnVal unVal -> evalUnVal unVal envRef
+  Expr'Val val -> return $ Expr'Val val
+  Expr'Set set -> evalSet set envRef
+  Expr'Get get -> evalGet get envRef
+  Expr'Define define -> evalDefine define envRef
+  Expr'Lambda lambda -> evalLambda lambda envRef
+  Expr'Fn _ -> return expr -- throw error?
+  Expr'List list -> evalList list envRef
+  Expr'FnCall call -> evalFnCall call envRef
+  Expr'Begin begin -> evalBegin begin envRef
+  Expr'ApiUnCall apiUnCall -> evalApiUnCall apiUnCall envRef
+
+forceVal :: (RuntimeThrower m) => Expr m -> Eval m Val
+forceVal (Expr'Val v) = return v
+forceVal _ = runtimeThrow RuntimeError'IncompatibleType
+
+evalRef :: (MonadIO m, RuntimeThrower m) => Ref -> IORef (Env m) -> Eval m (Expr m)
+evalRef Ref{symbol} envRef = do
+  env <- liftIO $ readIORef envRef
+  varLookup env symbol
+
+evalUnVal :: (MonadIO m, RuntimeThrower m) => UnVal m -> IORef (Env m) -> Eval m (Expr m)
+evalUnVal unVal envRef = case unVal of
+  UnVal'Const c -> return $ Expr'Val $ Val'Const c
+
+  UnVal'UnStruct UnStruct{m} -> do
+    members <- mapM (\(name,expr) -> (name,) <$> (forceVal =<< eval expr envRef)) (Map.toList m)
+    return $ Expr'Val $ Val'ApiVal $ ApiVal'Struct $ Struct (Map.fromList members)
+
+  UnVal'UnWrap UnWrap{w} -> do
+    w' <- eval w envRef
+    case w' of
+      Expr'Val (Val'Const c) -> return $ Expr'Val $ Val'ApiVal $ ApiVal'Wrap $ Wrap c
+      _ -> runtimeThrow RuntimeError'IncompatibleType
+
+  UnVal'UnEnumerator UnEnumerator{tag,m} -> do
+    case m of
+      Nothing -> return $ Expr'Val $ Val'ApiVal $ ApiVal'Enumerator $ Enumerator tag Nothing
+      Just members' -> do
+        members <- mapM (\(name,expr) -> (name,) <$> (forceVal =<< eval expr envRef)) (Map.toList members')
+        return $ Expr'Val $ Val'ApiVal $ ApiVal'Enumerator $ Enumerator tag (Just $ Map.fromList members)
+
+evalIf :: (MonadIO m, RuntimeThrower m) => If m -> IORef (Env m) -> Eval m (Expr m)
+evalIf If{cond, true, false} envRef = do
+  envRef' <- liftIO $ newIORef =<< readIORef envRef
+  v <- eval cond envRef'
+  case v of
+    Expr'Val (Val'Const (Const'Bool cond')) -> do
+      envRef'' <- liftIO $ newIORef =<< readIORef envRef
+      eval (if cond' then true else false) envRef''
+    _ -> runtimeThrow RuntimeError'IncompatibleType
+
+evalSet :: (MonadIO m, RuntimeThrower m) => Set m -> IORef (Env m) -> Eval m (Expr m)
+evalSet Set{var = var@(Symbol var'), expr} envRef = do
+  expr' <- eval expr envRef
+  env <- liftIO $ readIORef envRef
+  case Map.lookup var env of
+    Nothing -> runtimeThrow $ RuntimeError'UnknownVariable var'
+    Just v -> do
+      liftIO $ writeIORef v expr'
+      return expr'
+
+evalGet :: (MonadIO m, RuntimeThrower m) => Get m -> IORef (Env m) -> Eval m (Expr m)
+evalGet Get{path,expr} envRef = getter path =<< eval expr envRef
+
+getter :: (MonadIO m, RuntimeThrower m) => [Text] -> Expr m -> Eval m (Expr m)
+getter [] expr = return expr
+getter path expr =
+  case expr of
+    Expr'Val val -> case val of
+      Val'ApiVal apiVal -> getterApiVal path apiVal
+      _ -> runtimeThrow RuntimeError'IncompatibleType
+    _ -> runtimeThrow RuntimeError'IncompatibleType
+
+getterApiVal :: (MonadIO m, RuntimeThrower m) => [Text] -> ApiVal -> Eval m (Expr m)
+getterApiVal ("w":path) (ApiVal'Wrap (Wrap w)) = getter path (Expr'Val (Val'Const w))
+getterApiVal (mName:path) (ApiVal'Struct Struct{m}) =
+  case Map.lookup (MemberName mName) m of
+    Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    Just member -> getter path (Expr'Val member)
+getterApiVal (mName:path) (ApiVal'Enumerator Enumerator{m})
+  | mName == "tag" = runtimeThrow RuntimeError'IncompatibleType
+  | otherwise = case m >>= Map.lookup (MemberName mName) of
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+      Just member -> getter path (Expr'Val member)
+getterApiVal _ _ = runtimeThrow RuntimeError'IncompatibleType
+
+evalDefine :: (MonadIO m, RuntimeThrower m) => Define m -> IORef (Env m) -> Eval m (Expr m)
+evalDefine Define{var, expr} envRef = do
+  expr' <- eval expr envRef
+  env <- liftIO $ readIORef envRef
+  ref <- liftIO $ newIORef expr'
+  limit <- variableLimit <$> getOptions
+  addVarToEnv limit envRef var ref env
+  return expr'
+
+evalLambda :: (MonadIO m, RuntimeThrower m) => Lambda m -> IORef (Env m) -> Eval m (Expr m)
+evalLambda Lambda{params, expr} envRef = do
+  return . Expr'Fn . Fn $ \vals -> do
+    let keys = map fst params
+    let args = zip keys vals
+    let keysLen = length keys
+    let argsLen = length args
+    if keysLen /= argsLen
+      then runtimeThrow $ if keysLen < argsLen
+        then RuntimeError'TooManyArguments
+        else RuntimeError'TooFewArguments
+      else do
+        args' <- liftIO $ mapM newIORef (Map.fromList args)
+        limit <- variableLimit <$> getOptions
+        envRef' <- addEnvToEnv limit args' envRef
+        eval expr envRef'
+
+evalList :: (MonadIO m, RuntimeThrower m) => List m -> IORef (Env m)-> Eval m (Expr m)
+evalList List{list} envRef = do
+  list' <- mapM (\item -> eval item envRef) list
+  return . Expr'List $ List list'
+
+evalBegin :: (MonadIO m, RuntimeThrower m) => Begin m -> IORef (Env m) -> Eval m (Expr m)
+evalBegin Begin{exprs} envRef = case exprs of
+  [] -> return $ Expr'Val $ Val'Const $ Const'Null
+  _ -> last <$> mapM (\expr -> eval expr envRef) exprs
+
+evalFnCall :: (MonadIO m, RuntimeThrower m) => FnCall m -> IORef (Env m) -> Eval m (Expr m)
+evalFnCall FnCall{fn, args} envRef = do
+  val <- eval fn envRef
+  case val of
+    Expr'Fn (Fn fn') -> do
+      args' <- mapM (\arg -> eval arg envRef) args
+      fn' args'
+    Expr'Ref Ref{symbol} -> do
+      env <- liftIO $ readIORef envRef
+      v <- varLookup env symbol
+      case v of
+        Expr'Fn (Fn fn') -> do
+          args' <- mapM (\arg -> eval arg envRef) args
+          fn' args'
+        _ -> runtimeThrow $ RuntimeError'IncompatibleType
+    _ -> runtimeThrow RuntimeError'IncompatibleType
+
+evalApiUnCall :: (MonadIO m, RuntimeThrower m) => ApiUnCall m -> IORef (Env m) -> Eval m (Expr m)
+evalApiUnCall apiUnCall envRef = Expr'Val <$> case apiUnCall of
+  ApiUnCall'HollowUnCall c -> evalHollowUnCall c
+  ApiUnCall'WrapUnCall c -> evalWrapUnCall c envRef
+  ApiUnCall'StructUnCall c -> evalStructUnCall c envRef
+  ApiUnCall'EnumerationUnCall c -> evalEnumerationUnCall c envRef
+
+evalHollowUnCall :: (MonadIO m, RuntimeThrower m) => HollowUnCall -> Eval m Val
+evalHollowUnCall HollowUnCall{n} =
+  Eval . ReaderT $ \cfg ->
+    apiCall cfg $ ApiCall'Hollow n
+
+evalWrapUnCall :: (MonadIO m, RuntimeThrower m) => WrapUnCall m -> IORef (Env m) -> Eval m Val
+evalWrapUnCall WrapUnCall{n,w} envRef = do
+  expr <- eval w envRef
+  case expr of
+    Expr'Val (Val'Const c) -> Eval . ReaderT $ \cfg ->
+      apiCall cfg $ ApiCall'Wrap n (Wrap c)
+    _ -> runtimeThrow RuntimeError'IncompatibleType
+
+evalStructUnCall :: (MonadIO m, RuntimeThrower m) => StructUnCall m -> IORef (Env m) -> Eval m Val
+evalStructUnCall StructUnCall{n,m} envRef = do
+  m' <- mapM eval' m
+  Eval . ReaderT $ \cfg ->
+    apiCall cfg $ ApiCall'Struct n (Struct m')
+  where
+    eval' expr = do
+      expr' <- eval expr envRef
+      case expr' of
+        Expr'Val v -> return v
+        _ -> runtimeThrow RuntimeError'IncompatibleType
+
+evalEnumerationUnCall :: (MonadIO m, RuntimeThrower m) => EnumerationUnCall m -> IORef (Env m) -> Eval m Val
+evalEnumerationUnCall EnumerationUnCall{n,e} envRef = do
+  expr <- eval e envRef
+  case expr of
+    Expr'Val (Val'ApiVal (ApiVal'Enumerator e')) -> Eval . ReaderT $ \cfg ->
+      apiCall cfg $ ApiCall'Enumeration n e'
+    _ -> runtimeThrow RuntimeError'IncompatibleType
+
+emptyEnv :: RuntimeThrower m => IO (IORef (Env m))
+emptyEnv = do
+  eq <- newIORef eqExpr
+  neq <- newIORef neqExpr
+  concat' <- newIORef concatExpr
+  add <- newIORef addExpr
+  sub <- newIORef subExpr
+  mul <- newIORef mulExpr
+  div' <- newIORef divExpr
+  newIORef $ Map.fromList
+    [ ("==", eq)
+    , ("/=", neq)
+    , ("+", add)
+    , ("-", sub)
+    , ("*", mul)
+    , ("/", div')
+    , ("concat", concat')
+    ]
+
+numExpr :: RuntimeThrower m
+  => (Scientific -> Scientific -> Scientific)
+  -> (Int8 -> Int8 -> Int8)
+  -> (Int16 -> Int16 -> Int16)
+  -> (Int32 -> Int32 -> Int32)
+  -> (Int64 -> Int64 -> Int64)
+  -> (Word8 -> Word8 -> Word8)
+  -> (Word16 -> Word16 -> Word16)
+  -> (Word32 -> Word32 -> Word32)
+  -> (Word64 -> Word64 -> Word64)
+  -> Expr m
+numExpr num i8 i16 i32 i64 u8 u16 u32 u64 = Expr'Fn . Fn $ \args ->
+  case args of
+    (_:[]) -> runtimeThrow RuntimeError'TooFewArguments
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Const (Const'Number y))] -> return $
+      Expr'Val $ Val'Const $ Const'Number $ x `num` y
+
+    [Expr'Val (Val'Prim (Prim'I8 x)), Expr'Val (Val'Prim (Prim'I8 y))] -> toExpr $ x `i8` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'I8 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `i8` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'I8 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `i8` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'I16 x)), Expr'Val (Val'Prim (Prim'I16 y))] -> toExpr $ x `i16` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'I16 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `i16` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'I16 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `i16` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'I32 x)), Expr'Val (Val'Prim (Prim'I32 y))] -> toExpr $ x `i32` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'I32 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `i32` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'I32 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `i32` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'I64 x)), Expr'Val (Val'Prim (Prim'I64 y))] -> toExpr $ x `i64` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'I64 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `i64` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'I64 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `i64` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'U8 x)), Expr'Val (Val'Prim (Prim'U8 y))] -> toExpr $ x `u8` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'U8 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `u8` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'U8 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `u8` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'U16 x)), Expr'Val (Val'Prim (Prim'U16 y))] -> toExpr $ x `u16` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'U16 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `u16` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'U16 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `u16` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'U32 x)), Expr'Val (Val'Prim (Prim'U32 y))] -> toExpr $ x `u32` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'U32 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `u32` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'U32 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `u32` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'U64 x)), Expr'Val (Val'Prim (Prim'U64 y))] -> toExpr $ x `u64` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'U64 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `u64` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'U64 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `u64` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    (_:_:[]) -> runtimeThrow RuntimeError'IncompatibleType
+    _ -> runtimeThrow RuntimeError'TooManyArguments
+    where
+      toExpr v = return $ Expr'Val (toVal v)
+
+boolExpr :: RuntimeThrower m
+  => (Scientific -> Scientific -> Bool)
+  -> (Int8 -> Int8 -> Bool)
+  -> (Int16 -> Int16 -> Bool)
+  -> (Int32 -> Int32 -> Bool)
+  -> (Int64 -> Int64 -> Bool)
+  -> (Word8 -> Word8 -> Bool)
+  -> (Word16 -> Word16 -> Bool)
+  -> (Word32 -> Word32 -> Bool)
+  -> (Word64 -> Word64 -> Bool)
+  -> Expr m
+boolExpr num i8 i16 i32 i64 u8 u16 u32 u64 = Expr'Fn . Fn $ \args ->
+  case args of
+    (_:[]) -> runtimeThrow RuntimeError'TooManyArguments
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Const (Const'Number y))] -> toExpr $ x `num` y
+
+    [Expr'Val (Val'Prim (Prim'I8 x)), Expr'Val (Val'Prim (Prim'I8 y))] -> toExpr $ x `i8` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'I8 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `i8` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'I8 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `i8` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'I16 x)), Expr'Val (Val'Prim (Prim'I16 y))] -> toExpr $ x `i16` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'I16 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `i16` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'I16 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `i16` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'I32 x)), Expr'Val (Val'Prim (Prim'I32 y))] -> toExpr $ x `i32` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'I32 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `i32` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'I32 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `i32` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'I64 x)), Expr'Val (Val'Prim (Prim'I64 y))] -> toExpr $ x `i64` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'I64 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `i64` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'I64 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `i64` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'U8 x)), Expr'Val (Val'Prim (Prim'U8 y))] -> toExpr $ x `u8` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'U8 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `u8` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'U8 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `u8` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'U16 x)), Expr'Val (Val'Prim (Prim'U16 y))] -> toExpr $ x `u16` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'U16 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `u16` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'U16 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `u16` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'U32 x)), Expr'Val (Val'Prim (Prim'U32 y))] -> toExpr $ x `u32` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'U32 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `u32` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'U32 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `u32` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    [Expr'Val (Val'Prim (Prim'U64 x)), Expr'Val (Val'Prim (Prim'U64 y))] -> toExpr $ x `u64` y
+    [Expr'Val (Val'Const (Const'Number x)), Expr'Val (Val'Prim (Prim'U64 y))] -> case toBoundedInteger x of
+      Just x' -> toExpr $ x' `u64` y
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+    [Expr'Val (Val'Prim (Prim'U64 x)), Expr'Val (Val'Const (Const'Number y))] -> case toBoundedInteger y of
+      Just y' -> toExpr $ x `u64` y'
+      Nothing -> runtimeThrow RuntimeError'IncompatibleType
+
+    (_:_:[]) -> runtimeThrow RuntimeError'IncompatibleType
+    _ -> runtimeThrow RuntimeError'TooFewArguments
+    where
+      toExpr v = return $ Expr'Val (toVal v)
+
+eqExpr :: RuntimeThrower m => Expr m
+eqExpr = boolExpr (==) (==) (==) (==) (==) (==) (==) (==) (==)
+
+neqExpr :: RuntimeThrower m => Expr m
+neqExpr = boolExpr (/=) (/=) (/=) (/=) (/=) (/=) (/=) (/=) (/=)
+
+concatExpr :: RuntimeThrower m => Expr m
+concatExpr = Expr'Fn . Fn $ \args ->
+  case args of
+    (_:[]) -> runtimeThrow RuntimeError'TooFewArguments
+    [x, y] -> case (x,y) of
+      (Expr'Val (Val'Const (Const'String x')), Expr'Val (Val'Const (Const'String y'))) -> return $
+        Expr'Val . Val'Const . Const'String $ x' `mappend` y'
+      _ -> runtimeThrow RuntimeError'IncompatibleType
+    _ -> runtimeThrow RuntimeError'TooManyArguments
+
+addExpr :: RuntimeThrower m => Expr m
+addExpr = numExpr (+) (+) (+) (+) (+) (+) (+) (+) (+)
+
+subExpr :: RuntimeThrower m => Expr m
+subExpr = numExpr (-) (-) (-) (-) (-) (-) (-) (-) (-)
+
+mulExpr :: RuntimeThrower m => Expr m
+mulExpr = numExpr (*) (*) (*) (*) (*) (*) (*) (*) (*)
+
+divExpr :: RuntimeThrower m => Expr m
+divExpr = numExpr (/) div div div div div div div div
+
+--
+
+data ApiParser api = ApiParser
+  { hollow :: Map TypeName api
+  , struct :: Map TypeName (Val -> Maybe api)
+  , enumeration :: Map TypeName (Val -> Maybe api)
+  , wrap :: Map TypeName (Val -> Maybe api)
+  }
+
+parseApiCall :: ApiParser api -> ApiCall -> Maybe api
+parseApiCall ApiParser{hollow, struct, enumeration, wrap} = \case
+  ApiCall'Hollow n -> Map.lookup n hollow
+  ApiCall'Struct n s -> join $ ($ Val'ApiVal (ApiVal'Struct s)) <$> Map.lookup n struct
+  ApiCall'Enumeration n e -> join $ ($ Val'ApiVal (ApiVal'Enumerator e)) <$> Map.lookup n enumeration
+  ApiCall'Wrap n w -> join $ ($ Val'ApiVal (ApiVal'Wrap w)) <$> Map.lookup n wrap
diff --git a/library/Colorless/Runtime/Types.hs b/library/Colorless/Runtime/Types.hs
new file mode 100644
--- /dev/null
+++ b/library/Colorless/Runtime/Types.hs
@@ -0,0 +1,116 @@
+module Colorless.Runtime.Types
+  ( Symbol(..)
+  , Type(..)
+  , TypeName(..)
+  , MemberName(..)
+  , EnumeratorName(..)
+  , EnumeratorType(..)
+  , EnumerationType(..)
+  , StructType(..)
+  , HollowType(..)
+  , Prim(..)
+  , Const(..)
+  ) where
+
+import qualified Data.HashMap.Lazy as HML
+import Control.Monad (mzero)
+import Data.Aeson (FromJSON(..), FromJSONKey, ToJSONKey, Value(..), (.:), ToJSON(..))
+import Data.Text (Text)
+import Data.Map (Map)
+import Data.Int
+import Data.Word
+import Data.Scientific
+import Data.String (IsString)
+
+newtype Symbol = Symbol Text
+  deriving (Show, Eq, Ord, FromJSON, IsString)
+
+data Type = Type
+  { n :: TypeName
+  , p :: Maybe Type
+  } deriving (Show, Eq)
+
+instance FromJSON Type where
+  parseJSON = \case
+    String s -> pure $ Type (TypeName s) Nothing
+    Object o -> do
+      n <- o .: "n"
+      case HML.lookup "p" o of
+        Nothing -> pure $ Type n Nothing
+        Just p -> Type n <$> fmap Just (parseJSON p)
+    _ -> mzero
+
+newtype TypeName = TypeName Text
+  deriving (Show, Eq, Ord, FromJSON, IsString)
+
+newtype EnumeratorName = EnumeratorName Text
+  deriving (Show, Eq, Ord, FromJSON, ToJSON, IsString)
+
+newtype MemberName = MemberName Text
+  deriving (Show, Eq, Ord, FromJSON, ToJSON, ToJSONKey, FromJSONKey, IsString)
+
+data EnumeratorType = EnumeratorType
+  { m :: Maybe (Map MemberName Type)
+  } deriving (Show, Eq)
+
+data EnumerationType = EnumerationType
+  { e :: Map EnumeratorName EnumeratorType
+  , o :: Type
+  } deriving (Show, Eq)
+
+data StructType = StructType
+  { m :: Map MemberName Type
+  , o :: Type
+  } deriving (Show, Eq)
+
+data HollowType = HollowType
+  { o :: Type
+  } deriving (Show, Eq)
+
+data Prim
+  = Prim'Bool Bool
+  | Prim'I8 Int8
+  | Prim'I16 Int16
+  | Prim'I32 Int32
+  | Prim'I64 Int64
+  | Prim'U8 Word8
+  | Prim'U16 Word16
+  | Prim'U32 Word32
+  | Prim'U64 Word64
+  | Prim'String Text
+  deriving (Show, Eq)
+
+instance ToJSON Prim where
+  toJSON = \case
+    Prim'Bool b -> toJSON b
+    Prim'I8 i -> toJSON i
+    Prim'I16 i -> toJSON i
+    Prim'I32 i -> toJSON i
+    Prim'I64 i -> toJSON i
+    Prim'U8 u -> toJSON u
+    Prim'U16 u -> toJSON u
+    Prim'U32 u -> toJSON u
+    Prim'U64 u -> toJSON u
+    Prim'String s -> toJSON s
+
+data Const
+  = Const'Null
+  | Const'Bool Bool
+  | Const'String Text
+  | Const'Number Scientific
+  deriving (Show, Eq)
+
+instance ToJSON Const where
+  toJSON = \case
+    Const'Null -> Null
+    Const'Bool b -> Bool b
+    Const'String s -> String s
+    Const'Number n -> Number n
+
+instance FromJSON Const where
+  parseJSON = \case
+    Null -> pure $ Const'Null
+    Bool b -> pure $ Const'Bool b
+    String s -> pure $ Const'String s
+    Number n -> pure $ Const'Number n
+    _ -> mzero
diff --git a/library/Colorless/Runtime/Val.hs b/library/Colorless/Runtime/Val.hs
new file mode 100644
--- /dev/null
+++ b/library/Colorless/Runtime/Val.hs
@@ -0,0 +1,284 @@
+{-# LANGUAGE DeriveGeneric #-}
+module Colorless.Runtime.Val
+  ( Val(..)
+  , ApiVal(..)
+  , Wrap(..)
+  , Struct(..)
+  , Enumerator(..)
+  --
+  , FromVal(..)
+  , ToVal(..)
+  , getMember
+  , fromValFromJson
+  , combineObjects
+  ) where
+
+import qualified Data.HashMap.Lazy as HML
+import qualified Data.Map as Map
+import qualified Data.Vector as V
+import Control.Monad (mzero)
+import Control.Applicative ((<|>))
+import Data.Aeson
+import Data.Aeson.Types (parseMaybe)
+import Data.Map (Map)
+import Data.Text (Text)
+import Data.Int
+import Data.Word
+import Data.Scientific
+import GHC.Generics (Generic)
+
+import Colorless.Runtime.Types
+
+data Val
+  = Val'Const Const
+  | Val'Prim Prim
+  | Val'ApiVal ApiVal
+  | Val'List [Val]
+  deriving (Show, Eq)
+
+instance ToJSON Val where
+  toJSON = \case
+    Val'Const c -> toJSON c
+    Val'ApiVal v -> toJSON v
+    Val'List l -> toJSON l
+    Val'Prim p -> toJSON p
+
+instance FromJSON Val where
+  parseJSON = \case
+    Null -> return $ Val'Const Const'Null
+    Number n -> return $ Val'Const $ Const'Number n
+    String s -> return $ Val'Const $ Const'String s
+    Bool b -> return $ Val'Const $ Const'Bool b
+    Array arr -> Val'List <$> (mapM parseJSON $ V.toList arr)
+    v@Object{} -> Val'ApiVal <$> parseJSON v
+
+data ApiVal
+  = ApiVal'Wrap Wrap
+  | ApiVal'Struct Struct
+  | ApiVal'Enumerator Enumerator
+  deriving (Show, Eq)
+
+instance ToJSON ApiVal where
+  toJSON = \case
+    ApiVal'Wrap w -> toJSON w
+    ApiVal'Struct s -> toJSON s
+    ApiVal'Enumerator e -> toJSON e
+
+instance FromJSON ApiVal where
+  parseJSON v =
+    (ApiVal'Wrap <$> parseJSON v) <|>
+    (ApiVal'Enumerator <$> parseJSON v) <|>
+    (ApiVal'Struct <$> parseJSON v)
+
+data Wrap = Wrap
+  { w :: Const
+  } deriving (Show, Eq, Generic)
+
+instance ToJSON Wrap
+instance FromJSON Wrap
+
+data Struct = Struct
+  { m :: Map MemberName Val
+  } deriving (Show, Eq, Generic)
+
+instance ToJSON Struct where
+  toJSON Struct{m} = toJSON m
+
+instance FromJSON Struct where
+  parseJSON v = Struct <$> parseJSON v
+
+data Enumerator = Enumerator
+  { tag :: EnumeratorName
+  , m :: Maybe (Map MemberName Val)
+  } deriving (Show, Eq, Generic)
+
+instance ToJSON Enumerator where
+  toJSON Enumerator{tag,m} = object $ [ "tag" .= tag ] ++ case m of
+    Nothing -> []
+    Just m' -> concatMap (\(MemberName k,v) -> [ k .= v ]) (Map.toList m')
+
+instance FromJSON Enumerator where
+  parseJSON (Object o) = do
+    tag <- o .: "tag"
+    let tagless = HML.delete "tag" o
+    if HML.size o == 1
+      then pure $ Enumerator tag Nothing
+      else Enumerator tag <$> (Just <$> parseJSON (Object tagless))
+  parseJSON _ = mzero
+
+--
+
+class ToVal a where
+  toVal :: a -> Val
+
+instance ToVal () where
+  toVal () = Val'Const Const'Null
+
+instance ToVal Bool where
+  toVal b = Val'Const $ Const'Bool b
+
+instance ToVal Text where
+  toVal s = Val'Const $ Const'String s
+
+intToVal :: Integral a => a -> Val
+intToVal n = Val'Const $ Const'Number (fromInteger $ toInteger n)
+
+instance ToVal Int where
+  toVal = intToVal
+
+instance ToVal Int8 where
+  toVal i = Val'Prim $ Prim'I8 i
+
+instance ToVal Int16 where
+  toVal i = Val'Prim $ Prim'I16 i
+
+instance ToVal Int32 where
+  toVal i = Val'Prim $ Prim'I32 i
+
+instance ToVal Int64 where
+  toVal i = Val'Prim $ Prim'I64 i
+
+instance ToVal Word where
+  toVal = intToVal
+
+instance ToVal Word8 where
+  toVal u = Val'Prim $ Prim'U8 u
+
+instance ToVal Word16 where
+  toVal u = Val'Prim $ Prim'U16 u
+
+instance ToVal Word32 where
+  toVal u = Val'Prim $ Prim'U32 u
+
+instance ToVal Word64 where
+  toVal u = Val'Prim $ Prim'U64 u
+
+instance ToVal Float where
+    toVal f = Val'Const $ Const'Number $ fromFloatDigits f
+
+instance ToVal Double where
+    toVal d = Val'Const $ Const'Number $ fromFloatDigits d
+
+instance ToVal a => ToVal (Maybe a) where
+  toVal m = Val'ApiVal $ ApiVal'Enumerator $ case m of
+    Nothing -> Enumerator "None" Nothing
+    Just s -> Enumerator "Some" (Just $ Map.singleton "some" (toVal s))
+
+instance (ToVal a, ToVal b) => ToVal (Either a b) where
+  toVal m = Val'ApiVal $ ApiVal'Enumerator $ case m of
+    Left l -> Enumerator "Left" (Just $ Map.singleton "left" (toVal l))
+    Right r -> Enumerator "Right" (Just $ Map.singleton "right" (toVal r))
+
+instance ToVal a => ToVal [a] where
+  toVal list = Val'List $ map toVal list
+
+--
+
+class FromVal a where
+  fromVal :: Val -> Maybe a
+
+instance FromVal () where
+  fromVal (Val'Const Const'Null) = Just ()
+  fromVal _ = Nothing
+
+instance FromVal Bool where
+  fromVal (Val'Const (Const'Bool b)) = Just b
+  fromVal _ = Nothing
+
+instance FromVal Text where
+  fromVal (Val'Const (Const'String s)) = Just s
+  fromVal _ = Nothing
+
+intFromVal :: (Bounded i, Integral i) => Val -> Maybe i
+intFromVal (Val'Const (Const'Number n)) = toBoundedInteger n
+intFromVal _ = Nothing
+
+instance FromVal Int where
+  fromVal = intFromVal
+
+instance FromVal Int8 where
+  fromVal = \case
+    Val'Const (Const'Number n) -> toBoundedInteger n
+    Val'Prim (Prim'I8 i) -> Just i
+    _ -> Nothing
+
+instance FromVal Int16 where
+  fromVal = \case
+    Val'Const (Const'Number n) -> toBoundedInteger n
+    Val'Prim (Prim'I16 i) -> Just i
+    _ -> Nothing
+
+instance FromVal Int32 where
+  fromVal = \case
+    Val'Const (Const'Number n) -> toBoundedInteger n
+    Val'Prim (Prim'I32 i) -> Just i
+    _ -> Nothing
+
+instance FromVal Int64 where
+  fromVal = \case
+    Val'Const (Const'Number n) -> toBoundedInteger n
+    Val'Prim (Prim'I64 i) -> Just i
+    _ -> Nothing
+
+instance FromVal Word where
+  fromVal = intFromVal
+
+instance FromVal Word8 where
+  fromVal = \case
+    Val'Const (Const'Number n) -> toBoundedInteger n
+    Val'Prim (Prim'U8 u) -> Just u
+    _ -> Nothing
+
+instance FromVal Word16 where
+  fromVal = \case
+    Val'Const (Const'Number n) -> toBoundedInteger n
+    Val'Prim (Prim'U16 u) -> Just u
+    _ -> Nothing
+
+instance FromVal Word32 where
+  fromVal = \case
+    Val'Const (Const'Number n) -> toBoundedInteger n
+    Val'Prim (Prim'U32 u) -> Just u
+    _ -> Nothing
+
+instance FromVal Word64 where
+  fromVal = \case
+    Val'Const (Const'Number n) -> toBoundedInteger n
+    Val'Prim (Prim'U64 u) -> Just u
+    _ -> Nothing
+
+instance FromVal Float where
+  fromVal (Val'Const (Const'Number n)) = Just $ toRealFloat n
+  fromVal _ = Nothing
+
+instance FromVal Double where
+  fromVal (Val'Const (Const'Number n)) = Just $ toRealFloat n
+  fromVal _ = Nothing
+
+instance FromVal a => FromVal (Maybe a) where
+  fromVal (Val'ApiVal (ApiVal'Enumerator (Enumerator tag m))) = case (tag,m) of
+    ("Some",Just m') -> fromVal <$> Map.lookup "some" m'
+    ("None",Nothing) -> Just Nothing
+    _ -> Nothing
+  fromVal _ = Nothing
+
+instance (FromVal a, FromVal b) => FromVal (Either a b) where
+  fromVal (Val'ApiVal (ApiVal'Enumerator (Enumerator tag m))) = case (tag,m) of
+    ("Left",Just m') -> Map.lookup "left" m' >>= \l -> Left <$> fromVal l
+    ("Right",Just m') -> Map.lookup "right" m' >>= \r -> Right <$> fromVal r
+    _ -> Nothing
+  fromVal _ = Nothing
+
+instance FromVal a => FromVal [a] where
+  fromVal (Val'List list) = mapM fromVal list
+  fromVal _ = Nothing
+
+getMember :: FromVal a => Map MemberName Val -> MemberName -> Maybe a
+getMember m n = fromVal =<< Map.lookup n m
+
+fromValFromJson :: (FromVal b) => Value -> Maybe b
+fromValFromJson x = fromVal =<< parseMaybe parseJSON x
+
+combineObjects :: Value -> Value -> Value
+combineObjects (Object x) (Object y) = Object $ HML.union x y
+combineObjects _ _ = error "not objects"
diff --git a/library/Colorless/Types.hs b/library/Colorless/Types.hs
new file mode 100644
--- /dev/null
+++ b/library/Colorless/Types.hs
@@ -0,0 +1,123 @@
+{-# LANGUAGE DeriveGeneric #-}
+module Colorless.Types
+  ( Version(..)
+  , Major(..)
+  , Minor(..)
+  , Request(..)
+  , Response(..)
+  , ResponseError(..)
+  , RuntimeError(..)
+  , RuntimeThrower(..)
+  , Options(..)
+  ) where
+
+import Control.Monad (mzero)
+import Data.Aeson
+import Data.Text (Text)
+import GHC.Generics
+
+newtype Major = Major Int
+  deriving (Show, Eq, Generic, Num, Ord, Real, Integral, Enum)
+
+instance FromJSON Major
+instance ToJSON Major
+
+newtype Minor = Minor Int
+  deriving (Show, Eq, Generic, Num, Ord, Real, Integral, Enum)
+
+instance FromJSON Minor
+instance ToJSON Minor
+
+data Version = Version
+  { major :: Major
+  , minor :: Minor
+  } deriving (Show, Eq, Generic)
+
+instance ToJSON Version
+instance FromJSON Version
+
+data Request = Request
+  { meta :: Value
+  , calls :: [Value]
+  } deriving (Show, Eq)
+
+instance FromJSON Request where
+  parseJSON (Object o) = Request
+    <$> o .: "meta"
+    <*> o .: "calls"
+  parseJSON _ = mzero
+
+data RuntimeError
+  = RuntimeError'UnparsableFormat
+  | RuntimeError'UnrecognizedCall
+  | RuntimeError'VariableLimit
+  | RuntimeError'UnknownVariable Text
+  | RuntimeError'IncompatibleType
+  | RuntimeError'TooFewArguments
+  | RuntimeError'TooManyArguments
+  | RuntimeError'NoApiVersion
+  | RuntimeError'NoColorlessVersion
+  | RuntimeError'ApiMajorVersionTooLow
+  | RuntimeError'ApiMajorVersionTooHigh
+  | RuntimeError'ApiMinorVersionTooHigh
+  | RuntimeError'ColorlessMajorVersionTooLow
+  | RuntimeError'ColorlessMajorVersionTooHigh
+  | RuntimeError'ColorlessMinorVersionTooHigh
+  | RuntimeError'UnparsableMeta
+  | RuntimeError'UnparsableCalls
+  | RuntimeError'NoImplementation
+  | RuntimeError'NotMember
+  deriving (Show, Eq)
+
+instance ToJSON RuntimeError where
+  toJSON = \case
+    RuntimeError'UnparsableFormat -> e "UnparsableFormat"
+    RuntimeError'UnrecognizedCall -> object [ "tag" .= String "UnrecognizedCall" ]
+    RuntimeError'VariableLimit -> e "VariableLimit"
+    RuntimeError'UnknownVariable m -> object [ "tag" .= String "UnknownVariable", "name" .= m ]
+    RuntimeError'IncompatibleType -> e "IncompatibleType"
+    RuntimeError'TooFewArguments -> e "TooFewArguments"
+    RuntimeError'TooManyArguments -> e "TooManyArguments"
+    RuntimeError'NoApiVersion -> e "NoApiVersion"
+    RuntimeError'NoColorlessVersion -> e "NoColorlessVersion"
+    RuntimeError'ApiMajorVersionTooHigh -> e "ApiMajorVersionTooHigh"
+    RuntimeError'ApiMajorVersionTooLow -> e "ApiMajorVersionTooLow"
+    RuntimeError'ApiMinorVersionTooHigh -> e "ApiMinorVersionTooHigh"
+    RuntimeError'ColorlessMajorVersionTooHigh -> e "ColorlessMajorVersionTooHigh"
+    RuntimeError'ColorlessMajorVersionTooLow -> e "ColorlessMajorVersionTooLow"
+    RuntimeError'ColorlessMinorVersionTooHigh -> e "ColorlessMinorVersionTooHigh"
+    RuntimeError'UnparsableMeta -> e "UnparsableMeta"
+    RuntimeError'UnparsableCalls -> e "UnparsableCalls"
+    RuntimeError'NoImplementation -> e "NoImplementation"
+    RuntimeError'NotMember -> e "NotMember"
+    where
+      e s = object [ "tag" .= String s ]
+
+data ResponseError
+  = ResponseError'Service Value
+  | ResponseError'Runtime RuntimeError
+  deriving (Eq, Show)
+
+instance ToJSON ResponseError where
+  toJSON = \case
+    ResponseError'Service m -> object [ "tag" .= String "Service", "service" .= m ]
+    ResponseError'Runtime m -> object [ "tag" .= String "Runtime", "runtime" .= m ]
+
+data Response
+  = Response'Error ResponseError
+  | Response'Success Value
+  deriving (Show, Eq)
+
+instance ToJSON Response where
+  toJSON (Response'Error m) = object [ "tag" .= String "Error", "error" .= m ]
+  toJSON (Response'Success m) = object [ "tag" .= String "Success", "success" .= m ]
+
+class Monad m => RuntimeThrower m where
+  runtimeThrow :: RuntimeError -> m a
+
+instance RuntimeThrower IO where
+  runtimeThrow err = error $ "Runtime error - " ++ show err
+
+data Options = Options
+  { variableLimit :: Maybe Int
+  } deriving (Show, Eq)
diff --git a/package.yaml b/package.yaml
new file mode 100644
--- /dev/null
+++ b/package.yaml
@@ -0,0 +1,64 @@
+name: colorless
+version: '0.0.1'
+category: Web
+synopsis: Colorless
+description: Colorless
+maintainer: Joe Vargas
+license: BSD3
+extra-source-files:
+- package.yaml
+- README.md
+ghc-options: -Wall
+default-extensions:
+- ConstraintKinds
+- DeriveGeneric
+- DuplicateRecordFields
+- FlexibleContexts
+- FlexibleInstances
+- GADTs
+- GeneralizedNewtypeDeriving
+- KindSignatures
+- LambdaCase
+- MultiParamTypeClasses
+- NamedFieldPuns
+- OverloadedStrings
+- RankNTypes
+- ScopedTypeVariables
+- TupleSections
+- TypeApplications
+- TypeOperators
+library:
+  dependencies:
+  - aeson
+  - base >= 4.7 && < 5
+  - bytestring
+  - containers
+  - errors
+  - exceptions
+  - lifted-async
+  - monad-control
+  - monad-logger
+  - mtl
+  - random
+  - scientific
+  - text
+  - unordered-containers
+  - vector
+  source-dirs: library
+tests:
+  colorless-suite:
+    dependencies:
+    - aeson
+    - base >= 4.7 && < 5
+    - colorless
+    - containers
+    - hspec
+    - scientific
+    - text
+    - vector
+    ghc-options:
+    - -rtsopts
+    - -threaded
+    - -with-rtsopts=-N
+    main: Spec.hs
+    source-dirs: tests
diff --git a/src/Colorless/CodeGen/Types.hs b/src/Colorless/CodeGen/Types.hs
deleted file mode 100644
--- a/src/Colorless/CodeGen/Types.hs
+++ /dev/null
@@ -1,155 +0,0 @@
-module Colorless.CodeGen.Types
-  (
-  ) where
-
-import Pregame
-
-newtype FuncName = FuncName Text deriving (Show, Eq, Ord, IsString)
-newtype ArgName = ArgName Text deriving (Show, Eq, Ord, IsString)
-newtype Tag = Tag Text deriving (Show, Eq, Ord, IsString)
-newtype SumName = SumName Text deriving (Show, Eq, Ord, IsString)
-newtype SubtypeName = SubtypeName Text deriving (Show, Eq, Ord, IsString)
-newtype FieldName = FieldName Text deriving (Show, Eq, Ord, IsString)
-newtype OpaqueName = OpaqueName Text deriving (Show, Eq, Ord, IsString)
-newtype TypeParamName = TypeParamName Text deriving (Show, Eq, Ord, IsString)
-newtype Negative = Negative Integer deriving (Show, Eq, Num)
-newtype Positive = Positive Integer deriving (Show, Eq, Num)
-newtype Natural = Natural Integer deriving (Show, Eq, Num)
-newtype Rational = Rational (Integer, Integer) deriving (Show, Eq)
-newtype Version = Version (Integer, Integer, Integer) deriving (Show, Eq, Ord)
-newtype HttpDirectory = HttpDirectory [Text] deriving (Show, Eq, Monoid)
-newtype HttpPort = HttpPort Int deriving (Show, Eq)
-newtype SpecName = SpecName Text deriving (Show, Eq, IsString)
-newtype DomainName = DomainName Text deriving (Show, Eq, IsString)
-
-data PrimType
-  = PrimTypeUnit
-  | PrimTypeU8
-  | PrimTypeU16
-  | PrimTypeU32
-  | PrimTypeU64
-  | PrimTypeI8
-  | PrimTypeI16
-  | PrimTypeI32
-  | PrimTypeI64
-  | PrimTypeF32
-  | PrimTypeF64
-  | PrimTypeBool
-  | PrimTypeChar
-  | PrimTypeStr
-  | PrimTypeInt
-  | PrimTypeNeg
-  | PrimTypePos
-  | PrimTypeNat
-  | PrimTypeRat
-  deriving (Show, Eq)
-
-data PrimRef
-  = PrimRefUnit
-  | PrimRefU8 Word8
-  | PrimRefU16 Word16
-  | PrimRefU32 Word32
-  | PrimRefU64 Word64
-  | PrimRefI8 Int8
-  | PrimRefI16 Int16
-  | PrimRefI32 Int32
-  | PrimRefI64 Int64
-  | PrimRefF32 Float
-  | PrimRefF64 Double
-  | PrimRefBool Bool
-  | PrimRefChar Char
-  | PrimRefStr Text
-  | PrimRefInt Integer
-  | PrimRefNeg Negative
-  | PrimRefPos Positive
-  | PrimRefNat Natural
-  | PrimRefRat Rational
-  deriving (Show, Eq)
-
-data Type
-  = TypePrim PrimType
-  | TypeOpaque OpaqueName
-  deriving (Show, Eq)
-
-data TypeRef
-  = TypeRefPrimType PrimType
-  | TypeRefOpaque OpaqueRef
-  deriving (Show, Eq)
-
-data TypeParamRef
-  = TypeParamRefPrimRef PrimRef
-  | TypeParamRefPrimType PrimType
-  | TypeParamRefOpaqueRef OpaqueRef
-  deriving (Show, Eq)
-
-data TypeParam = TypeParam
-  { _name :: TypeParamName
-  , _ref :: TypeParamRef
-  } deriving (Show, Eq)
-
-data OpaqueRef = OpaqueRef
-  { _name :: OpaqueName
-  , _params :: [TypeParamRef]
-  } deriving (Show, Eq)
-
-data FuncDef = FuncDef
-  { _args :: [(ArgName, TypeRef)]
-  , _tags :: Set Tag
-  } deriving (Show, Eq)
-
-data SumDef = SumDef
-  { _params :: [TypeParamRef]
-  , _subtypes :: Map SubtypeName [TypeRef]
-  , _tags :: Set Tag
-  } deriving (Show, Eq)
-
-data ProductDef = ProductDef
-  { _params :: [TypeParamRef]
-  , _fields :: Map FieldName TypeRef
-  , _tags :: Set Tag
-  } deriving (Show, Eq)
-
-data OpaqueDef
-  = OpaqueDefSum SumDef
-  | OpaqueDefProduct ProductDef
-  deriving (Show, Eq)
-
-data ServiceDef = ServiceDef
-  { _opaques :: Map OpaqueName OpaqueDef
-  , _funcs :: Map FuncName FuncDef
-  , _tags :: Set Tag
-  } deriving (Show, Eq)
-
-data HttpFormat
-  = HttpFormatJson
-  deriving (Show, Eq)
-
-data HttpMeta
-  = HttpMetaHeader
-  deriving (Show, Eq)
-
-data HttpImpl = HttpImpl
-  { _directory :: HttpDirectory
-  , _port :: HttpPort
-  , _meta :: HttpMeta
-  , _format :: HttpFormat
-  } deriving (Show, Eq)
-
-data Impl
-  = ImplHttp HttpImpl
-  deriving (Show, Eq)
-
-data Domain = Domain
-  { _name :: DomainName
-  , _service :: ServiceDef
-  , _impl :: Impl
-  } deriving (Show, Eq)
-
-data SpecDef = SpecDef
-  { _name :: SpecName
-  , _domains :: [Domain]
-  } deriving (Show, Eq)
-
-data Specs = Specs
-  { _defs :: Map Version SpecDef
-  } deriving (Show, Eq)
diff --git a/tests/AstSpec.hs b/tests/AstSpec.hs
new file mode 100644
--- /dev/null
+++ b/tests/AstSpec.hs
@@ -0,0 +1,124 @@
+module AstSpec (spec) where
+
+import qualified Data.Vector as V
+import qualified Data.Map as Map
+import Test.Hspec
+import Data.Aeson
+import Data.Aeson.Types
+
+import Colorless.Runtime.Types
+import Colorless.Runtime.Ast
+
+parseAst :: Value -> Maybe Ast
+parseAst = parseMaybe parseJSON
+
+spec :: Spec
+spec = do
+  describe "parse basic types" $ do
+    it "TypeName" $ shouldBe
+      (parseMaybe parseJSON (String "MyName"))
+      (Just $ TypeName "MyName")
+
+    it "MemberName" $ shouldBe
+      (parseMaybe parseJSON (String "MyName"))
+      (Just $ MemberName "MyName")
+
+    context "Type" $ do
+      it "string only" $ shouldBe
+        (parseMaybe parseJSON (String "MyType"))
+        (Just $ Type "MyType" Nothing)
+
+      it "object with no param" $ shouldBe
+        (parseMaybe parseJSON $ object ["n" .= String "MyType"])
+        (Just $ Type "MyType" Nothing)
+
+      it "object with param" $ shouldBe
+        (parseMaybe parseJSON $ object ["n" .= String "MyType", "p" .= String "MyParam"])
+        (Just $ Type "MyType" (Just $ Type "MyParam" Nothing))
+
+  describe "parse Ast" $ do
+    it "Ref" $ shouldBe
+      (parseAst $ object ["@" .= String "myRef"])
+      (Just $ Ast'Ref $ Ref "myRef")
+
+    context "If" $ do
+      it "simple" $ shouldBe
+        (parseAst $ Array $ V.fromList ["if", Bool True, "true", "false"])
+        (Just $ Ast'If $ If
+          (Ast'Const $ Const'Bool True)
+          (Ast'Const $ Const'String "true")
+          (Ast'Const $ Const'String "false"))
+
+    context "Set" $ do
+      it "simple" $ shouldBe
+        (parseAst $ Array $ V.fromList ["set", "myVar", Bool False])
+        (Just $ Ast'Set $ Set "myVar" (Ast'Const $ Const'Bool False))
+
+    context "Get" $ do
+      it "simple yet not semantically correct" $ shouldBe
+        (parseAst $ Array $ V.fromList ["get", Array $ V.fromList ["a","b","c"], Bool False])
+        (Just $ Ast'Get $ Get ["a","b","c"] (Ast'Const $ Const'Bool False))
+
+    context "Define" $ do
+      it "simple" $ shouldBe
+        (parseAst $ Array $ V.fromList ["def", "myVar", Bool True])
+        (Just $ Ast'Define $ Define "myVar" (Ast'Const $ Const'Bool True))
+
+    context "Lambda" $ do
+      it "simple" $ shouldBe
+        (parseAst $ Array $ V.fromList ["fn", Array $ V.fromList [ object [ "myVar" .= String "Int64" ] ], Bool True])
+        (Just $ Ast'Lambda $ Lambda [("myVar", Type "Int64" Nothing)] (Ast'Const $ Const'Bool True))
+
+    context "List" $ do
+      it "simple" $ shouldBe
+        (parseAst $ object [ "List" .= [String "hello"] ])
+        (Just $ Ast'List $ List [Ast'Const $ Const'String "hello"])
+
+    context "Begin" $ do
+      it "simple" $ shouldBe
+        (parseAst $ Array $ V.fromList ["begin", Bool True])
+        (Just $ Ast'Begin $ Begin [Ast'Const $ Const'Bool True])
+
+    context "FnCall" $ do
+      it "simple" $ shouldBe
+        (parseAst $ Array $ V.fromList ["someFn", "one", Bool False])
+        (Just $ Ast'FnCall $ FnCall (Ast'Ref $ Ref "someFn") [Ast'Const $ Const'String "one", Ast'Const $ Const'Bool False])
+
+    context "EnumerationCall" $ do
+      it "simple" $ shouldBe
+        (parseAst $ object [ "n" .= String "MyEnum", "e" .= object [ "tag" .= String "MyTag" ] ])
+        (Just $ Ast'EnumerationCall $ EnumerationCall "MyEnum" (Ast'Enumerator $ Enumerator "MyTag" Nothing))
+
+    context "StructCall" $ do
+      it "simple" $ shouldBe
+        (parseAst $ object [ "n" .= String "MyStruct", "m" .= object [ "x" .= Bool True ] ])
+        (Just $ Ast'StructCall $ StructCall "MyStruct" (Map.fromList [("x", Ast'Const $ Const'Bool True)]))
+
+    context "HollowCall" $ do
+      it "simple" $ shouldBe
+        (parseAst $ object [ "n" .= String "MyCall" ])
+        (Just $ Ast'HollowCall $ HollowCall "MyCall")
+
+    context "Enumerator" $ do
+      it "simple without members" $ shouldBe
+        (parseAst $ object [ "tag" .= String "MyTag" ])
+        (Just $ Ast'Enumerator $ Enumerator "MyTag" Nothing)
+      it "simple with members" $ shouldBe
+        (parseAst $ object [ "tag" .= String "MyTag", "x" .= Bool True ])
+        (Just $ Ast'Enumerator $ Enumerator "MyTag" (Just $ Map.fromList [("x", Ast'Const $ Const'Bool True)]))
+
+    context "Struct" $ do
+      it "simple" $ shouldBe
+        (parseAst $ object [ "key0" .= Bool True ])
+        (Just $ Ast'Struct $ Struct $ Map.fromList [("key0", Ast'Const $ Const'Bool True)])
+
+    context "Const" $ do
+      it "Bool" $ shouldBe
+        (parseAst $ Bool True)
+        (Just $ Ast'Const $ Const'Bool True)
+      it "String" $ shouldBe
+        (parseAst $ String "Hello")
+        (Just $ Ast'Const $ Const'String "Hello")
+      it "Number" $ shouldBe
+        (parseAst $ Number 12345)
+        (Just $ Ast'Const $ Const'Number 12345)
diff --git a/tests/ExprSpec.hs b/tests/ExprSpec.hs
new file mode 100644
--- /dev/null
+++ b/tests/ExprSpec.hs
@@ -0,0 +1,13 @@
+module ExprSpec where
+
+import Test.Hspec
+
+-- import Colorless.Types
+-- import Colorless.Runtime.Types
+-- import Colorless.Runtime.Expr
+
+spec :: Spec
+spec = do
+  describe "expr" $ do
+    it "" $ do
+      True `shouldBe` True
diff --git a/tests/Spec.hs b/tests/Spec.hs
new file mode 100644
--- /dev/null
+++ b/tests/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/tests/ValSpec.hs b/tests/ValSpec.hs
new file mode 100644
--- /dev/null
+++ b/tests/ValSpec.hs
@@ -0,0 +1,31 @@
+module ValSpec (spec) where
+
+import qualified Data.Map as Map
+import Test.Hspec
+import Data.Aeson
+import Data.Aeson.Types
+import Data.Text (Text)
+
+import Colorless.Runtime.Types
+import Colorless.Runtime.Val
+
+spec :: Spec
+spec = do
+  describe "parse basic types from json" $ do
+    it "Enumerator" $ shouldBe
+      (parseMaybe parseJSON $ object [ "tag" .= ("None" :: Text) ])
+      (Just $ Val'ApiVal $ ApiVal'Enumerator $ Enumerator "None" Nothing)
+    it "Struct" $ shouldBe
+      (parseMaybe parseJSON $ object [ "x" .= True ])
+      (Just $ Val'ApiVal $ ApiVal'Struct $ Struct $ Map.fromList [("x", Val'Const $ Const'Bool True)] )
+    it "Struct" $ shouldBe
+      (parseMaybe parseJSON $ object [ "x" .= object [ "tag" .= ("None" :: Text) ] ])
+      (Just $ Val'ApiVal $ ApiVal'Struct $ Struct $ Map.fromList [("x", Val'ApiVal $ ApiVal'Enumerator $ Enumerator "None" Nothing)] )
+  describe "parse types from val" $ do
+    context "Option" $ do
+      it "None" $ shouldBe
+        (fromVal $ Val'ApiVal $ ApiVal'Enumerator $ Enumerator "None" Nothing)
+        (Just Nothing :: Maybe (Maybe Bool))
+      it "Some" $ shouldBe
+        (fromVal $ Val'ApiVal $ ApiVal'Enumerator $ Enumerator "Some" $ Just $ Map.fromList [("some", Val'Const $ Const'Bool $ True)])
+        (Just (Just True) :: Maybe (Maybe Bool))
