initial
diff --git a/JQ.hs b/JQ.hs
new file mode 100644
index 0000000..ca8df79
--- /dev/null
+++ b/JQ.hs
@@ -0,0 +1,157 @@
+module JQ where
+import Text.JSON
+import Text.JSON.String
+import Data.Maybe
+import Data.List (sortBy,sort,groupBy)
+import Data.Function (on)
+import Data.Ord (comparing)
+import Control.Monad
+import Control.Monad.Writer
+import Control.Monad.List
+import Control.Monad.Reader
+
+type Path = [Either Int String]
+
+type Program = JSValue -> [(JSValue, Path)]
+
+type JQ = ReaderT JSValue (WriterT Path [])
+
+runJQ :: JQ a -> JSValue -> [a]
+runJQ prog val = map fst $ runWriterT $ runReaderT prog val
+
+(>|) :: JQ JSValue -> JQ a -> JQ a
+a >| b = do
+ val <- a
+ local (const val) b
+
+collect :: JQ a -> JQ [a]
+collect prog = do
+ arg <- ask
+ return $ runJQ prog arg
+
+collectPaths :: JQ a -> JQ [(a,Path)]
+collectPaths prog = do
+ arg <- ask
+ return $ runWriterT $ runReaderT prog arg
+
+insert :: JSValue -> (JSValue, Path) -> JSValue
+insert base (replace, []) = replace
+insert (JSArray values) (replace, ((Left n):rest)) = JSArray values'
+ where
+ (left, (_:right)) = splitAt n values
+ values' = left ++ [replace] ++ right
+insert (JSObject obj) (replace, ((Right k):rest))= JSObject $ toJSObject obj'
+ where
+ withoutK = filter ((/= k) . fst) $ fromJSObject obj
+ obj' = (k, replace):withoutK
+
+
+eqj a b = JSBool $ a == b
+
+
+liftp :: (JSValue -> JSValue) -> JQ JSValue
+liftp f = liftM f ask
+
+idp = undefined
+failp t = []
+
+constp :: JSValue -> Program
+constp t t' = idp t
+
+anyj :: [JSValue] -> Bool
+anyj values = any isTrue values
+ where
+ isTrue (JSBool False) = False
+ isTrue (JSNull) = False
+ isTrue _ = True
+
+selectp prog = do
+ match <- collect prog
+ guard $ anyj match
+ ask
+
+constStr :: String -> JQ JSValue
+constStr = return . JSString . toJSString
+
+constInt :: Int -> JQ JSValue
+constInt = return . JSRational False . toRational
+
+updatep p = do
+ t <- ask
+ liftM (foldl insert t) $ collectPaths p
+
+arrayp prog = liftM JSArray $ collect prog
+
+
+childp' :: JSValue -> JQ JSValue
+childp' (JSArray values) = msum [tell [Left i] >> return v | (v,i) <- zip values [0..]]
+childp' (JSObject obj) = msum [tell [Right k] >> return v | (k,v) <- fromJSObject obj]
+childp' _ = mzero
+
+childp = ask >>= childp'
+
+--findp :: Program -> Program
+findp prog = do
+ found <- collect prog
+ if anyj found then ask else childp >| findp prog
+
+groupp prog = do
+ list <- ask
+ case list of
+ JSArray values -> do
+ marked <- forM values $ \v -> do
+ m <- collect (return v >| prog)
+ return (m,v)
+ msum $
+ map (return . JSArray . map snd) $
+ groupBy ((==) `on` fst) $
+ sortBy (comparing fst) $
+ marked
+ _ -> return JSNull
+
+
+
+
+withArray f (JSArray values) = JSArray $ f values
+withArray f x = x
+
+callp "select" [p] = selectp p
+callp "find" [p] = findp p
+callp "set" [p] = updatep p
+callp "sort" [] = liftp (withArray sort)
+callp "group" [p] = groupp p
+
+lookupj :: JSValue -> JSValue -> JQ JSValue
+lookupj (JSArray values) (JSRational _ n) = do
+ let idx = round n
+ tell [Left idx]
+ if idx >= 0 && idx < length values
+ then return $ values !! idx
+ else return $ JSNull
+lookupj (JSObject obj) (JSString s) = do
+ tell [Right (fromJSString s)]
+ case (lookup (fromJSString s) (fromJSObject obj)) of
+ Just x -> return x
+ Nothing -> return JSNull
+lookupj _ _ = mzero
+
+
+plusj (JSRational _ n1) (JSRational _ n2) = JSRational True (n1 + n2)
+plusj (JSString s1) (JSString s2) = JSString $ toJSString (fromJSString s1 ++ fromJSString s2)
+plusj (JSArray a1) (JSArray a2) = JSArray $ a1 ++ a2
+
+
+js :: JSON a => a -> JSValue
+js = showJSON
+
+index s = do
+ v <- ask
+ lookupj v (js s)
+
+
+dictp progs = do
+ liftM (JSObject . toJSObject) $ forM progs $ \(k,v) -> do
+ JSString k' <- k
+ v' <- v
+ return (fromJSString k', v')
+
diff --git a/Lexer.x b/Lexer.x
new file mode 100644
index 0000000..700c69e
--- /dev/null
+++ b/Lexer.x
@@ -0,0 +1,101 @@
+{
+module Lexer where
+import Control.Monad.Error
+}
+
+%wrapper "monadUserState"
+
+$digit = 0-9
+$alpha = [a-zA-Z_]
+@reserved = "."|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"=="|"+"
+@ident = $alpha [$alpha $digit]*
+@string = \" ($printable)* \"
+
+
+tokens :-
+
+<0> $white+ ;
+<0> @reserved { tok TRes }
+<0> @ident { tok TIdent }
+<0> $digit+ { tok $ TInt . read }
+
+
+<0> \" { enterString }
+<string> \" { leaveString }
+<string> ($printable # [\"\\]) { pushString id }
+<string> \\ [\"\\\/] { pushString (drop 1) }
+<string> \\ [nrt] { pushString (escape . drop 1) }
+--<string> \\ 'u' [0-9a-fA-F]{4}
+-- { pushString (parseUnicode . drop 2) }
+
+-- @string { \s -> TString $ init $ tail s}
+
+
+{
+
+escape :: String -> String
+escape "r" = "\r"
+escape "n" = "\n"
+escape "t" = "\t"
+
+getState :: Alex AlexState
+getState = Alex $ \s -> Right (s, s)
+
+getUserState :: Alex AlexUserState
+getUserState = liftM alex_ust getState
+
+setUserState :: AlexUserState -> Alex ()
+setUserState s' = Alex $ \s -> Right (s{alex_ust = s'}, ())
+
+alexEOF = return $ Nothing
+
+enterString input len = do
+ setUserState []
+ alexSetStartCode string
+ skip input len
+
+pushString f i@(p, _, s) len = do
+ buf <- getUserState
+ setUserState (buf ++ [f $ take len s])
+ skip i len
+
+leaveString input len = do
+ s <- getUserState
+ alexSetStartCode 0
+ return $ Just $ TString $ concat s
+
+
+tok f (p,_,s) len = return $ Just $ f (take len s)
+data Token = TRes String | TString String | TIdent String | TInt Int
+
+instance Show Token where
+ show (TRes t) = "token " ++ t
+ show (TString t) = "string " ++ t
+ show (TIdent t) = "identifier " ++ t
+ show (TInt t) = "integer " ++ show t
+
+
+type AlexUserState = [String]
+
+alexInitUserState = undefined
+
+wrapError (Alex scanner) = Alex $ \s -> case scanner s of
+ Left message -> Left (message ++ " at " ++ showpos (alex_pos s))
+ where
+ showpos (AlexPn off line col) = "line " ++ show line ++ ", column " ++ show col
+ x -> x
+
+scanner = do
+ tok <- wrapError alexMonadScan
+ case tok of
+ Nothing -> do
+ s <- getState
+ case alex_scd s of
+ 0 -> return []
+ string -> alexError "Unterminated string literal"
+ Just tok -> liftM (tok:) scanner
+
+runLexer :: String -> Either String [Token]
+runLexer input = runAlex input scanner
+
+}
\ No newline at end of file
diff --git a/Main.hs b/Main.hs
new file mode 100644
index 0000000..695520c
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,22 @@
+import Parser
+import Lexer
+import JQ
+import Text.JSON
+import Text.JSON.String
+import System.Environment
+import Control.Monad
+import System.IO
+
+
+parseJS :: String -> JSValue
+parseJS s = case runGetJSON readJSValue s of
+ Left err -> error err
+ Right val -> val
+
+
+main = do
+ [program] <- getArgs
+ json <- liftM parseJS $ hGetContents stdin
+ case runLexer program >>= runParser of
+ Left err -> putStrLn err
+ Right program -> mapM_ (putStrLn . encode) (runJQ program json)
\ No newline at end of file
diff --git a/Parser.y b/Parser.y
new file mode 100644
index 0000000..544fe5b
--- /dev/null
+++ b/Parser.y
@@ -0,0 +1,78 @@
+{
+module Parser where
+import Lexer
+import JQ
+import Text.JSON
+import Debug.Trace
+import Data.List
+import Control.Monad.Error
+import Control.Monad.Reader
+}
+
+%name runParser Exp
+%tokentype { Token }
+
+%monad { Either String }
+%error { \t -> fail $ "parse error: unexpected " ++ if null t then [] else (show $ head t) }
+
+%token
+ '|' { TRes "|" }
+ '.' { TRes "." }
+ '[' { TRes "[" }
+ ']' { TRes "]" }
+ '{' { TRes "{" }
+ '}' { TRes "}" }
+ '(' { TRes "(" }
+ ')' { TRes ")" }
+ ',' { TRes "," }
+ ':' { TRes ":" }
+ '==' { TRes "==" }
+ '+' { TRes "+" }
+ Ident { TIdent $$ }
+ String { TString $$ }
+ Int { TInt $$ }
+
+%left '|'
+%left ','
+%nonassoc '=='
+%left '+'
+
+%%
+
+Exp
+ : Exp '|' Exp { $1 >| $3 }
+ | Exp ',' Exp { $1 `mplus` $3 }
+ | Exp '==' Exp { liftM2 eqj $1 $3 }
+ | Exp '+' Exp { liftM2 plusj $1 $3 }
+ | Term { $1 }
+
+ExpD
+ : ExpD '|' ExpD { $1 >| $3 }
+ | ExpD '==' ExpD { liftM2 eqj $1 $3 }
+ | Term { $1 }
+
+
+Term
+ : '.' { ask }
+ | Term '.' Ident { $1 >| index $3 }
+ | '.' Ident { index $2 }
+ | String { constStr $1 }
+ | Term '[' Exp ']' { do {t <- $1; i <- $3; lookupj t i} }
+ | Term '[' ']' { $1 >| childp }
+ | '(' Exp ')' { $2 }
+ | '[' Exp ']' { arrayp $2 }
+ | Int { constInt $1 }
+ | '{' MkDict '}' { dictp $2 }
+ | Ident '(' Exp ')' { callp $1 [$3] }
+ | Ident { callp $1 [] }
+
+MkDict
+ : { [] }
+ | MkDictPair { [$1] }
+ | MkDictPair ',' MkDict { $1:$3 }
+
+MkDictPair
+ : Ident ':' ExpD { (constStr $1, $3) }
+ | Ident { (constStr $1, index $1) }
+ | String ':' ExpD { (constStr $1, $3) }
+ | '(' Exp ')' ':' ExpD{ ($2, $5) }