packages feed

hpaco-lib 0.11.0.6 → 0.16.1.0

raw patch · 20 files changed

+1267/−585 lines, 20 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Text.HPaco.Readers.Paco: instance Exception ParseError
- Text.HPaco.Readers.Paco: instance Typeable ParseError
+ Data.Variant: instance Ord Variant
+ Data.Variant: vamap :: ((Variant, Variant) -> a) -> Variant -> [a]
+ Data.Variant.ToFrom: class FromVariant a
+ Data.Variant.ToFrom: class ToVariant a
+ Data.Variant.ToFrom: fromVariant :: FromVariant a => Variant -> a
+ Data.Variant.ToFrom: instance [incoherent] (FromVariant a, FromVariant b) => FromVariant [(a, b)]
+ Data.Variant.ToFrom: instance [incoherent] (FromVariant a, FromVariant b, FromVariant c, ToVariant d) => ToVariant (a -> b -> c -> d)
+ Data.Variant.ToFrom: instance [incoherent] (FromVariant a, FromVariant b, ToVariant c) => ToVariant (a -> b -> c)
+ Data.Variant.ToFrom: instance [incoherent] (FromVariant a, ToVariant b) => ToVariant (a -> b)
+ Data.Variant.ToFrom: instance [incoherent] (ToVariant a, ToVariant b) => ToVariant [(a, b)]
+ Data.Variant.ToFrom: instance [incoherent] FromVariant Bool
+ Data.Variant.ToFrom: instance [incoherent] FromVariant Double
+ Data.Variant.ToFrom: instance [incoherent] FromVariant Int
+ Data.Variant.ToFrom: instance [incoherent] FromVariant Integer
+ Data.Variant.ToFrom: instance [incoherent] FromVariant String
+ Data.Variant.ToFrom: instance [incoherent] FromVariant Variant
+ Data.Variant.ToFrom: instance [incoherent] FromVariant a => FromVariant (Maybe a)
+ Data.Variant.ToFrom: instance [incoherent] FromVariant a => FromVariant [a]
+ Data.Variant.ToFrom: instance [incoherent] ToVariant Bool
+ Data.Variant.ToFrom: instance [incoherent] ToVariant Double
+ Data.Variant.ToFrom: instance [incoherent] ToVariant Int
+ Data.Variant.ToFrom: instance [incoherent] ToVariant Integer
+ Data.Variant.ToFrom: instance [incoherent] ToVariant String
+ Data.Variant.ToFrom: instance [incoherent] ToVariant Variant
+ Data.Variant.ToFrom: instance [incoherent] ToVariant a => ToVariant (Maybe a)
+ Data.Variant.ToFrom: instance [incoherent] ToVariant a => ToVariant [a]
+ Data.Variant.ToFrom: toVariant :: ToVariant a => a -> Variant
+ Text.HPaco.AST.AST: astDeps :: AST -> [String]
+ Text.HPaco.AST.AST: defAST :: AST
+ Text.HPaco.AST.Statement: SourcePositionStatement :: FilePath -> Int -> Statement
+ Text.HPaco.Readers.Paco.Basics: anyQuotedString :: ParsecT String PacoState IO [Char]
+ Text.HPaco.Readers.Paco.Basics: assertStartOfInput :: Parser ()
+ Text.HPaco.Readers.Paco.Basics: assertStartOfLine :: Parser ()
+ Text.HPaco.Readers.Paco.Basics: braces :: Parser a -> Parser a
+ Text.HPaco.Readers.Paco.Basics: discard :: Parser a -> Parser ()
+ Text.HPaco.Readers.Paco.Basics: doubleQuotedString :: ParsecT String PacoState IO [Char]
+ Text.HPaco.Readers.Paco.Basics: identifier :: Parser String
+ Text.HPaco.Readers.Paco.Basics: manySepBy :: Parser a -> Parser b -> Parser [a]
+ Text.HPaco.Readers.Paco.Basics: singleQuotedString :: ParsecT String PacoState IO [Char]
+ Text.HPaco.Readers.Paco.Basics: ss :: a -> Parser a
+ Text.HPaco.Readers.Paco.Basics: ss_ :: Parser ()
+ Text.HPaco.Readers.Paco.Expressions: expression :: Parser Expression
+ Text.HPaco.Readers.Paco.ParserInternals: PacoState :: FilePath -> [(String, Statement)] -> [String] -> Maybe String -> Reader -> PacoState
+ Text.HPaco.Readers.Paco.ParserInternals: addDef :: String -> Statement -> Parser ()
+ Text.HPaco.Readers.Paco.ParserInternals: data PacoState
+ Text.HPaco.Readers.Paco.ParserInternals: data ParseError :: *
+ Text.HPaco.Readers.Paco.ParserInternals: defaultPacoState :: PacoState
+ Text.HPaco.Readers.Paco.ParserInternals: fillExtension :: FilePath -> String -> FilePath
+ Text.HPaco.Readers.Paco.ParserInternals: instance Exception ParseError
+ Text.HPaco.Readers.Paco.ParserInternals: instance Typeable ParseError
+ Text.HPaco.Readers.Paco.ParserInternals: psBasePath :: PacoState -> FilePath
+ Text.HPaco.Readers.Paco.ParserInternals: psDefs :: PacoState -> [(String, Statement)]
+ Text.HPaco.Readers.Paco.ParserInternals: psDeps :: PacoState -> [String]
+ Text.HPaco.Readers.Paco.ParserInternals: psHandleInclude :: PacoState -> Reader
+ Text.HPaco.Readers.Paco.ParserInternals: psIncludeExtension :: PacoState -> Maybe String
+ Text.HPaco.Readers.Paco.ParserInternals: resolveDef :: String -> Parser Statement
+ Text.HPaco.Readers.Paco.ParserInternals: type Parser a = ParsecT String PacoState IO a
+ Text.HPaco.Readers.Paco.Statements: statement :: Parser Statement
+ Text.HPaco.Readers.Paco.Statements: statements :: Parser [Statement]
+ Text.HPaco.Writers.Dependencies: writeDependencies :: String -> AST -> String
+ Text.HPaco.Writers.Internal.WrapMode: instance Eq WrapMode
+ Text.HPaco.Writers.JsonLisp: instance JWSWrite (JWS ())
+ Text.HPaco.Writers.JsonLisp: instance JWSWrite AST
+ Text.HPaco.Writers.JsonLisp: instance JWSWrite Expression
+ Text.HPaco.Writers.JsonLisp: instance JWSWrite Statement
+ Text.HPaco.Writers.JsonLisp: instance JWSWrite String
+ Text.HPaco.Writers.JsonLisp: writeJsonLisp :: Writer
+ Text.HPaco.Writers.Run.Library: loadLibrary :: String -> Variant
- Text.HPaco.AST.AST: AST :: Statement -> [(Identifier, Statement)] -> AST
+ Text.HPaco.AST.AST: AST :: Statement -> [(Identifier, Statement)] -> [String] -> AST
- Text.HPaco.AST.Statement: ForStatement :: Identifier -> Expression -> Statement -> Statement
+ Text.HPaco.AST.Statement: ForStatement :: (Maybe Identifier) -> Identifier -> Expression -> Statement -> Statement

Files

Data/Variant.hs view
@@ -15,7 +15,7 @@         , scopeMerge         , keys         , values-        , vmap+        , vmap, vamap         , wrapf, wrapfs         , wrapf1, wrapfs1         , call, callMaybe, callDef@@ -45,6 +45,21 @@ instance Eq ([Variant] -> Variant)     where (==) a b = False +instance Ord Variant+    where+        compare (String a) b = compare a $ flatten b+        compare a (String b) = compare (flatten a) b+        compare (Double a) b = compare a $ toDouble b+        compare a (Double b) = compare (toDouble a) b+        compare (Integer a) b = compare a $ toInteger b+        compare a (Integer b) = compare (toInteger a) b+        compare (Bool a) b = compare a $ toBool b+        compare a (Bool b) = compare (toBool a) b+        compare Null Null = EQ+        compare Null _ = LT+        compare _ Null = GT+        compare _ _ = EQ+ flatten :: Variant -> String flatten (String s) = s flatten (Integer i) = show i@@ -178,6 +193,9 @@  vmap :: (Variant -> a) -> Variant -> [a] vmap f v = map f $ values v++vamap :: ((Variant, Variant) -> a) -> Variant -> [a]+vamap f v = map f $ toAList v  wrapfs :: (Variant -> [Variant] -> Variant) -> Variant -> Variant wrapfs f s = Function $ f s
+ Data/Variant/ToFrom.hs view
@@ -0,0 +1,78 @@+{-#LANGUAGE FlexibleInstances, UndecidableInstances, IncoherentInstances #-}+module Data.Variant.ToFrom where++import Data.Variant+import Prelude hiding (toInteger)++class ToVariant a where+    toVariant :: a -> Variant++class FromVariant a where+    fromVariant :: Variant -> a++-- Variant itself implements to/from variant+instance ToVariant Variant where+    toVariant = id+instance FromVariant Variant where+    fromVariant = id++-- Various scalar instances++instance ToVariant String where+    toVariant = String+instance FromVariant String where+    fromVariant = flatten++instance ToVariant Bool where+    toVariant = Bool+instance FromVariant Bool where+    fromVariant = toBool++instance ToVariant Double where+    toVariant = Double+instance FromVariant Double where+    fromVariant = toDouble++instance ToVariant Integer where+    toVariant = Integer+instance FromVariant Integer where+    fromVariant = toInteger++instance ToVariant Int where+    toVariant = Integer . fromIntegral+instance FromVariant Int where+    fromVariant = fromIntegral . toInteger++-- Maybes of to/from variant types implement to/from variant+instance ToVariant a => ToVariant (Maybe a) where+    toVariant Nothing = Null+    toVariant (Just a) = toVariant a++instance FromVariant a => FromVariant (Maybe a) where+    fromVariant Null = Nothing+    fromVariant a = Just (fromVariant a)++-- Lists of variants+instance (ToVariant a, ToVariant b) => ToVariant [(a,b)] where+    toVariant xs =+        let (keys, values) = unzip xs+            vkeys = map toVariant keys+            vvalues = map toVariant values+        in AList $ zip vkeys vvalues++instance (FromVariant a, FromVariant b) => FromVariant [(a,b)] where+    fromVariant = map (\(k,v) -> (fromVariant k, fromVariant v)) . toAList++instance ToVariant a => ToVariant [a] where+    toVariant xs = List (map toVariant xs)++instance FromVariant a => FromVariant [a] where+    fromVariant = map fromVariant . values++-- Functions, up to 3 arguments+instance (FromVariant a, ToVariant b) => ToVariant (a -> b) where+    toVariant f = Function (\(x:_) -> toVariant (f $ fromVariant x))+instance (FromVariant a, FromVariant b, ToVariant c) => ToVariant (a -> b -> c) where+    toVariant f = Function (\(x:y:_) -> toVariant (f (fromVariant x) (fromVariant y)))+instance (FromVariant a, FromVariant b, FromVariant c, ToVariant d) => ToVariant (a -> b -> c -> d) where+    toVariant f = Function (\(x:y:z:_) -> toVariant (f (fromVariant x) (fromVariant y) (fromVariant z)))
Text/HPaco/AST/AST.hs view
@@ -6,5 +6,13 @@ data AST =     AST { astRootStatement :: Statement         , astDefs :: [(Identifier,Statement)]+        , astDeps :: [String]         }         deriving (Show)++defAST :: AST+defAST =+    AST { astRootStatement = NullStatement+        , astDefs = []+        , astDeps = []+        }
Text/HPaco/AST/Statement.hs view
@@ -4,11 +4,12 @@ import Text.HPaco.AST.Identifier (Identifier)  data Statement = NullStatement+               | SourcePositionStatement FilePath Int                | StatementSequence [Statement]                | PrintStatement Expression                | IfStatement Expression Statement Statement                | LetStatement Identifier Expression Statement-               | ForStatement Identifier Expression Statement+               | ForStatement (Maybe Identifier) Identifier Expression Statement                | CallStatement Identifier                | SwitchStatement Expression [(Expression, Statement)]                deriving (Show, Eq)
Text/HPaco/Optimizer.hs view
@@ -29,15 +29,17 @@             then PrintStatement e             else optimizeStatement $ PrintStatement e' +-- Turn SourcePositionStatements into Null statements so that they are removed+optimizeStatement (SourcePositionStatement _ _) = NullStatement+ optimizeStatement (StatementSequence xs) =-    let xs' = filter (/= NullStatement) (map optimizeStatement xs)+    let xs' = fusePrints $ filter (/= NullStatement) (map optimizeStatement xs)     in case xs' of         -- flatten nested statement sequences         (StatementSequence ss):rem -> optimizeStatement . StatementSequence $ ss ++ rem-        -- combine print statements-        (PrintStatement (StringLiteral lhs)):(PrintStatement (StringLiteral rhs)):rem ->-            optimizeStatement . StatementSequence $-                (PrintStatement $ StringLiteral (lhs ++ rhs)):rem+        -- reduce statement sequences with only one statement in them down+        -- to that single statement+        s:[] -> s         -- remove empty statement sequences         [] -> NullStatement         otherwise -> StatementSequence xs'@@ -55,10 +57,10 @@         stmt' = optimizeStatement stmt     in LetStatement id e' stmt' -optimizeStatement (ForStatement id e stmt) =+optimizeStatement (ForStatement iter id e stmt) =     let e' = optimizeExpression e         stmt' = optimizeStatement stmt-    in ForStatement id e' stmt'+    in ForStatement iter id e' stmt'  optimizeStatement (SwitchStatement e branches) =     let e' = optimizeExpression e@@ -68,6 +70,12 @@ optimizeStatement s = s  +fusePrints :: [Statement] -> [Statement]+fusePrints ((PrintStatement (StringLiteral lhs)):(PrintStatement (StringLiteral rhs)):rem) =+    fusePrints $ PrintStatement (StringLiteral $ lhs ++ rhs):fusePrints rem+fusePrints (s:rem) = s:fusePrints rem+fusePrints [] = []+ optimizeExpression :: Expression -> Expression optimizeExpression e =     if isConst e@@ -88,7 +96,7 @@  evaluateConstExpression :: Expression -> Expression evaluateConstExpression e =-    let rs = Run.RunState { Run.rsScope = Null, Run.rsAST = AST { astDefs = [], astRootStatement = NullStatement }, Run.rsOptions = Run.defaultOptions }+    let rs = Run.RunState { Run.rsScope = Null, Run.rsAST = defAST, Run.rsOptions = Run.defaultOptions }         v = unsafePerformIO $ evalStateT (Run.runExpression e) rs     in fromVariant v 
Text/HPaco/Readers/Paco.hs view
@@ -1,4 +1,3 @@-{-#LANGUAGE DeriveDataTypeable, StandaloneDeriving #-} module Text.HPaco.Readers.Paco     ( readPaco     )@@ -7,44 +6,23 @@ import Control.Monad import Control.Monad.IO.Class import Text.HPaco.Reader+import Text.HPaco.Readers.Paco.ParserInternals+import Text.HPaco.Readers.Paco.Basics+import Text.HPaco.Readers.Paco.Statements import Text.HPaco.AST.AST import Text.HPaco.AST.Statement import Text.HPaco.AST.Expression-import Text.Parsec.Prim-import Text.Parsec.Char-import Text.Parsec.Combinator-import Text.Parsec.Pos (SourcePos, sourceLine, sourceColumn)-import Text.Parsec.String hiding (Parser)-import Text.Parsec.Error (ParseError)-import Control.Exception (throw, Exception)-import Data.Typeable+import Control.Exception (throw) import System.IO (withFile, IOMode (ReadMode)) import System.IO.Strict import System.FilePath -instance Exception ParseError-deriving instance Typeable ParseError--data PacoState = PacoState-                    { psBasePath :: FilePath-                    , psDefs :: [(String, Statement)]-                    , psIncludeExtension :: Maybe String-                    }--type Parser a = ParsecT String PacoState IO a--defaultPacoState :: PacoState-defaultPacoState = PacoState-                        { psBasePath = ""-                        , psDefs = []-                        , psIncludeExtension = Nothing-                        }- readPaco :: Reader readPaco filename =     let pstate = defaultPacoState                     { psBasePath = takeDirectory filename                     , psIncludeExtension = renull $ takeExtension filename+                    , psHandleInclude = readPaco                     }     in readPacoWithState pstate filename     where renull "" = Nothing@@ -60,464 +38,11 @@  document :: Parser AST document = do-    stmts <- many statement+    stmts <- statements     eof     pstate <- getState     return $ AST                  { astRootStatement = StatementSequence stmts                 , astDefs = psDefs pstate+                , astDeps = psDeps pstate                 }---- Statement parsers--statement :: Parser Statement-statement = try ifStatement -          <|> try withStatement-          <|> try switchStatement-          <|> try forStatement-          <|> try defStatement-          <|> try callStatement-          <|> try commentStatement-          <|> try includeStatement-          <|> try interpolateStatement-          <|> try newlineStatement-          <|> try escapeSequenceStatement-          <|> rawTextStatement--commentStatement :: Parser Statement-commentStatement = do-    string "{%--"-    manyTill-        (try (discard commentStatement) <|> discard anyChar)-        (try $ string "--%}")-    return NullStatement--includeStatement :: Parser Statement-includeStatement = do-    (basename, innerContext) <- complexTag "include" inner-    dirname <- psBasePath `liftM` getState-    extension <- psIncludeExtension `liftM` getState-    let fn0 = joinPath [ dirname, basename ]-    let fn = maybe fn0 (fillExtension fn0) extension-    src <- liftIO $ withFile fn ReadMode hGetContents-    subAst <- liftIO $ readPaco fn src-    let stmt = astRootStatement subAst-    return $ maybe stmt (\(ident, expr) -> LetStatement ident expr stmt) innerContext-    where-        path :: Parser String-        path = many1 $ try $ noneOf " \t\r\n%"--        inner :: Parser (String, Maybe (String, Expression))-        inner = do-            basename <- path-            ss_-            innerContext <- optionMaybe $ try (ss_ >> string "with" >> ss_ >> letPair)-            return (basename, innerContext)--interpolateStatement :: Parser Statement-interpolateStatement = do-    char '{'-    em <- option (Just EscapeHTML) escapeMode-    ss_-    expr <- expression-    ss_-    char '}'-    let expr' = maybe-                    expr-                    (\m -> EscapeExpression m expr)-                    em-    return $ PrintStatement $ expr'--rawTextStatement :: Parser Statement-rawTextStatement = do-    chrs <- many1 $ noneOf "{\\\n"-    return $ PrintStatement $ StringLiteral chrs--newlineStatement :: Parser Statement-newlineStatement = do-    char '\n'-    ss_-    return $ PrintStatement $ StringLiteral "\n"--escapeSequenceStatement :: Parser Statement-escapeSequenceStatement = do-    char '\\'-    c <- anyChar-    case c of-        '\n' -> return NullStatement-        otherwise -> return $ PrintStatement $ StringLiteral [ '\\', c ]--ifStatement :: Parser Statement-ifStatement = do-        cond <- complexTag "if" expression-        trueStmts <- many statement-        let trueBranch = StatementSequence trueStmts-        falseBranch <- option NullStatement $ try elseBranch-        simpleTag "endif"-        return $ IfStatement cond trueBranch falseBranch-        where elseBranch =-                do-                    simpleTag "else"-                    stmts <- many statement-                    return . StatementSequence $ stmts--withStatement :: Parser Statement-withStatement = withOrForStatement LetStatement "with"--forStatement :: Parser Statement-forStatement = withOrForStatement ForStatement "for"--withOrForStatement :: (String -> Expression -> Statement -> Statement) -> String -> Parser Statement-withOrForStatement ctor keyword = do-    (ident, expr) <- complexTag keyword letPair-    stmts <- many $ try statement-    simpleTag $ "end" ++ keyword-    return $ ctor ident expr $ StatementSequence stmts--letPair :: Parser (String, Expression)-letPair = do-    expr <- expression-    ss_-    ident <- option "." $ try $ char ':' >> ss_ >> identifier-    ss_-    return (ident, expr)--switchStatement :: Parser Statement-switchStatement = do-    masterExpr <- complexTag "switch" expression-    ss_-    branches <- many switchBranch-    ss_-    simpleTag "endswitch"-    return $ SwitchStatement masterExpr branches-    where switchBranch = do-            ss_-            switchExpr <- complexTag "case" expression-            stmts <- many statement-            simpleTag "endcase"-            ss_-            return (switchExpr, StatementSequence stmts)--defStatement :: Parser Statement-defStatement = do-    name <- complexTag "def" identifier-    body <- many statement-    simpleTag "enddef"-    addDef name $ StatementSequence body-    return NullStatement--callStatement :: Parser Statement-callStatement = do-    name <- complexTag "call" identifier-    optional $ char '\n'-    return $ CallStatement name--simpleTag tag = complexTag tag (return ())-complexTag tag inner = -    let go = do-            string "{%" -            ss_ -            string tag -            ss_ -            i <- inner-            ss_-            string "%}" -            return i-        standalone = do-            assertStartOfLine-            ss_-            v <- go-            char '\n'-            return v--    in try standalone <|> try go----- Expression parsers--expression = booleanExpression--booleanExpression =-    binaryExpression-        [("&&", OpBooleanAnd),-         ("||", OpBooleanOr),-         ("^^", OpBooleanXor)]-        setOperationExpression--setOperationExpression =-    binaryExpression-        [("in", OpInList),-         ("contains", Flipped OpInList)]-        comparativeExpression--comparativeExpression =-    binaryExpression-        [("==", OpEquals),-         ("!==", OpNotEquals),-         ("=", OpLooseEquals),-         ("!=", OpLooseNotEquals),-         (">=", OpNotLess),-         (">", OpGreater),-         ("<=", OpNotGreater),-         ("<", OpLess)]-        additiveExpression--additiveExpression =-    binaryExpression-        [("+", OpPlus), ("-", OpMinus)]-        multiplicativeExpression--multiplicativeExpression =-    binaryExpression-        [("*", OpMul), ("/", OpDiv), ("%", OpMod)]-        (try traditionalFunctionCallExpression <|> postfixExpression)--binaryExpression :: [(String, BinaryOperator)] -> (Parser Expression) -> Parser Expression-binaryExpression opMap innerParser = do-    let rem :: Parser (BinaryOperator, Expression)-        rem = do-            ss_-            opStr <- foldl1 (<|>) $ map (try . string . fst) opMap-            ss_-            let Just op = lookup opStr opMap-            e <- innerParser-            return (op, e)-    left <- innerParser-    right <- many $ try rem-    return $ foldl combine left right-    where-        combine :: Expression -> (BinaryOperator, Expression) -> Expression-        combine lhs (op, rhs) = BinaryExpression op lhs rhs--traditionalFunctionCallExpression = do-    char '$'-    args <- manySepBy (try expression) ss_-    return $ FunctionCallExpression (head args) (tail args)--postfixExpression = do-    left <- (try prefixExpression <|> simpleExpression)-    postfixes <- many postfix-    return $ foldl combine left postfixes-    where-        combine :: Expression -> (Expression -> Expression) -> Expression-        combine l f = f l--prefixExpression = do-    ss_-    operator <- unaryOperator-    ss_-    expr <- (try prefixExpression <|> simpleExpression)-    return $ UnaryExpression operator expr--unaryOperator = do-    let opMap = [("not", OpNot)]-    opStr <- foldl1 (<|>) $ map (try . string . fst) opMap-    let Just op = lookup opStr opMap-    return op-    -postfix = try memberAccessPostfix-        <|> try indexPostfix-        <|> try functionCallPostfix--memberAccessPostfix :: Parser (Expression -> Expression)-memberAccessPostfix = do-    char '.'-    expr <- StringLiteral `liftM` identifier-    return $ \l -> BinaryExpression OpMember l expr--indexPostfix :: Parser (Expression -> Expression)-indexPostfix = do-    ss_-    char '['-    e <- expression-    char ']'-    ss_-    return $ \l -> BinaryExpression OpMember l e--functionCallPostfix :: Parser (Expression -> Expression)-functionCallPostfix = do-    char '('-    args <- manySepBy (try expression) (try $ ss_ >> char ',' >> ss_)-    ss_-    char ')'-    return $ \l -> FunctionCallExpression l args--simpleExpression :: Parser Expression-simpleExpression  =  floatLiteral-                 <|> intLiteral-                 <|> stringLiteral-                 <|> listExpression-                 <|> alistExpression-                 <|> varRefExpr-                 <|> bracedExpression--bracedExpression :: Parser Expression-bracedExpression = do-    char '('-    ss_-    inner <- expression-    ss_-    char ')'-    return inner--listExpression :: Parser Expression-listExpression = do-    char '['-    ss_-    items <- manySepBy expression (ss_ >> char ',' >> ss_)-    ss_-    optional $ char ',' >> ss_-    char ']'-    return $ ListExpression items--alistExpression :: Parser Expression-alistExpression = do-    char '{'-    ss_-    items <- option [] $ try $ manySepBy elem $ char ','-    ss_-    optional $ char ',' >> ss_-    char '}'-    return $ AListExpression items-    where-        elem :: Parser (Expression, Expression)-        elem = do-            ss_-            key <- expression-            ss_ >> char ':' >> ss_-            value <- expression-            ss_-            return (key, value)--intLiteral :: Parser Expression-intLiteral = do-    sign <- option '+' $ oneOf "+-"-    str <- many1 digit-    let str' = if sign == '-' then sign:str else str-    return . IntLiteral . read $ str'--floatLiteral :: Parser Expression-floatLiteral = do-    str <- (try dpd <|> try pd)-    return . FloatLiteral . read $ str-    where-        dpd = do-            sign <- option '+' $ oneOf "+-"-            intpart <- many1 digit-            char '.'-            fracpart <- many digit-            let str = intpart ++ "." ++ fracpart-            return $ if sign == '-' then sign:str else str-        pd = do-            sign <- option '+' $ oneOf "+-"-            char '.'-            fracpart <- many1 digit-            let str = "0." ++ fracpart-            return $ if sign == '-' then sign:str else str--stringLiteral :: Parser Expression-stringLiteral = do-    str <- anyQuotedString-    return . StringLiteral $ str--varRefExpr :: Parser Expression-varRefExpr = do-    id <- (string "." <|> identifier)-    return $ VariableReference id---- Parser state management--addDef :: String -> Statement -> Parser ()-addDef name value =-    modifyState (\s -> s { psDefs = ((name, value):psDefs s) })--resolveDef :: String -> Parser Statement-resolveDef name = do-    defs <- psDefs `liftM` getState-    let val = lookup name defs-    maybe-        (unexpected $ name ++ " is not defined.")-        return-        val---- Auxiliary parsers--ss :: a -> Parser a-ss a = skipMany space >> return a--ss_ :: Parser ()-ss_ = ss ()--braces :: Parser a -> Parser a-braces inner = do-    char '{'-    ss_-    v <- inner-    ss_-    char '}'-    return v--escapeMode :: Parser (Maybe EscapeMode)-escapeMode = (char '!' >> return Nothing)-          <|> (char '@' >> return (Just EscapeURL))--identifier :: Parser String-identifier = do-    x <- letter <|> char '_'-    xs <- many $ letter <|> digit <|> char '_'-    return $ x:xs--anyQuotedString = singleQuotedString <|> doubleQuotedString--singleQuotedString = quotedString '\''-doubleQuotedString = quotedString '"'--quotedString qc = do-    char qc-    str <- many $ quotedStringChar qc-    char qc-    return str--quotedStringChar qc =-    try escapedChar-    <|> noneOf [qc]--escapedChar = do-    char '\\'-    c2 <- anyChar-    return $ case c2 of-                'n' -> '\n'-                'r' -> '\r'-                'b' -> '\b'-                't' -> '\t'-                otherwise -> c2--discard :: Parser a -> Parser ()-discard p = p >> return ()--manySepBy :: Parser a -> Parser b -> Parser [a]-manySepBy elem sep = do-    h <- try elem-    t <- many (try $ sep >> elem)-    return $ h:t--assertStartOfInput :: Parser ()-assertStartOfInput = do-    pos <- getPosition-    if sourceLine pos == 1 && sourceColumn pos == 1-        then return ()-        else unexpected "start of input"--assertStartOfLine :: Parser ()-assertStartOfLine = do-    pos <- getPosition-    if sourceColumn pos == 1-        then return ()-        else unexpected "start of line"--fillExtension :: FilePath -> String -> FilePath-fillExtension fp ext =-    let ext0 = takeExtension fp-    in if null ext0-        then replaceExtension fp ext-        else fp
+ Text/HPaco/Readers/Paco/Basics.hs view
@@ -0,0 +1,95 @@+module Text.HPaco.Readers.Paco.Basics+    ( module Text.Parsec.Combinator+    , module Text.Parsec.Char+    , module Text.Parsec.Prim+    , module Text.Parsec.String+    , ss, ss_+    , braces+    , identifier+    , anyQuotedString, singleQuotedString, doubleQuotedString+    , discard+    , manySepBy+    , assertStartOfLine, assertStartOfInput+    )+where++import Text.HPaco.Readers.Paco.ParserInternals+import Text.Parsec.Char+import Text.Parsec.Combinator+import Text.Parsec.Pos (SourcePos, sourceLine, sourceColumn, sourceName)+import Text.Parsec.Prim+import Text.Parsec.String hiding (Parser)+import Control.Monad.IO.Class+import System.IO.Strict++-- Auxiliary parsers++ss :: a -> Parser a+ss a = skipMany space >> return a++ss_ :: Parser ()+ss_ = ss ()++braces :: Parser a -> Parser a+braces inner = do+    char '{'+    ss_+    v <- inner+    ss_+    char '}'+    return v++identifier :: Parser String+identifier = do+    x <- letter <|> char '_'+    xs <- many $ letter <|> digit <|> char '_'+    return $ x:xs++anyQuotedString = singleQuotedString <|> doubleQuotedString++singleQuotedString = quotedString '\''+doubleQuotedString = quotedString '"'++quotedString qc = do+    char qc+    str <- many $ quotedStringChar qc+    char qc+    return str++quotedStringChar qc =+    try escapedChar+    <|> noneOf [qc]++escapedChar :: Parser Char+escapedChar = do+    char '\\'+    c2 <- anyChar+    return $ case c2 of+                'n' -> '\n'+                'r' -> '\r'+                'b' -> '\b'+                't' -> '\t'+                otherwise -> c2++discard :: Parser a -> Parser ()+discard p = p >> return ()++manySepBy :: Parser a -> Parser b -> Parser [a]+manySepBy elem sep = do+    h <- try elem+    t <- many (try $ sep >> elem)+    return $ h:t++assertStartOfInput :: Parser ()+assertStartOfInput = do+    pos <- getPosition+    if sourceLine pos == 1 && sourceColumn pos == 1+        then return ()+        else unexpected "start of input"++assertStartOfLine :: Parser ()+assertStartOfLine = do+    pos <- getPosition+    if sourceColumn pos == 1+        then return ()+        else unexpected "start of line"
+ Text/HPaco/Readers/Paco/Expressions.hs view
@@ -0,0 +1,202 @@+module Text.HPaco.Readers.Paco.Expressions+    ( expression+    )+where++import Control.Monad+import Text.HPaco.Readers.Paco.Basics+import Text.HPaco.Readers.Paco.ParserInternals+import Text.HPaco.AST.Statement+import Text.HPaco.AST.Expression++expression = booleanExpression++booleanExpression =+    binaryExpression+        [("&&", OpBooleanAnd),+         ("||", OpBooleanOr),+         ("^^", OpBooleanXor)]+        setOperationExpression++setOperationExpression =+    binaryExpression+        [("in", OpInList),+         ("contains", Flipped OpInList)]+        comparativeExpression++comparativeExpression =+    binaryExpression+        [("==", OpEquals),+         ("!==", OpNotEquals),+         ("=", OpLooseEquals),+         ("!=", OpLooseNotEquals),+         (">=", OpNotLess),+         (">", OpGreater),+         ("<=", OpNotGreater),+         ("<", OpLess)]+        additiveExpression++additiveExpression =+    binaryExpression+        [("+", OpPlus), ("-", OpMinus)]+        multiplicativeExpression++multiplicativeExpression =+    binaryExpression+        [("*", OpMul), ("/", OpDiv), ("%", OpMod)]+        (try traditionalFunctionCallExpression <|> postfixExpression)++binaryExpression :: [(String, BinaryOperator)] -> (Parser Expression) -> Parser Expression+binaryExpression opMap innerParser = do+    let rem :: Parser (BinaryOperator, Expression)+        rem = do+            ss_+            opStr <- foldl1 (<|>) $ map (try . string . fst) opMap+            ss_+            let Just op = lookup opStr opMap+            e <- innerParser+            return (op, e)+    left <- innerParser+    right <- many $ try rem+    return $ foldl combine left right+    where+        combine :: Expression -> (BinaryOperator, Expression) -> Expression+        combine lhs (op, rhs) = BinaryExpression op lhs rhs++traditionalFunctionCallExpression = do+    char '$'+    args <- manySepBy (try expression) ss_+    return $ FunctionCallExpression (head args) (tail args)++postfixExpression = do+    left <- (try prefixExpression <|> simpleExpression)+    postfixes <- many postfix+    return $ foldl combine left postfixes+    where+        combine :: Expression -> (Expression -> Expression) -> Expression+        combine l f = f l++prefixExpression = do+    ss_+    operator <- unaryOperator+    ss_+    expr <- (try prefixExpression <|> simpleExpression)+    return $ UnaryExpression operator expr++unaryOperator = do+    let opMap = [("not", OpNot)]+    opStr <- foldl1 (<|>) $ map (try . string . fst) opMap+    let Just op = lookup opStr opMap+    return op+    +postfix = try memberAccessPostfix+        <|> try indexPostfix+        <|> try functionCallPostfix++memberAccessPostfix :: Parser (Expression -> Expression)+memberAccessPostfix = do+    char '.'+    expr <- StringLiteral `liftM` identifier+    return $ \l -> BinaryExpression OpMember l expr++indexPostfix :: Parser (Expression -> Expression)+indexPostfix = do+    ss_+    char '['+    e <- expression+    char ']'+    ss_+    return $ \l -> BinaryExpression OpMember l e++functionCallPostfix :: Parser (Expression -> Expression)+functionCallPostfix = do+    char '('+    args <- manySepBy (try expression) (try $ ss_ >> char ',' >> ss_)+    ss_+    char ')'+    return $ \l -> FunctionCallExpression l args++simpleExpression :: Parser Expression+simpleExpression  =  floatLiteral+                 <|> intLiteral+                 <|> stringLiteral+                 <|> listExpression+                 <|> alistExpression+                 <|> varRefExpr+                 <|> bracedExpression++bracedExpression :: Parser Expression+bracedExpression = do+    char '('+    ss_+    inner <- expression+    ss_+    char ')'+    return inner++listExpression :: Parser Expression+listExpression = do+    char '['+    ss_+    items <- manySepBy expression (ss_ >> char ',' >> ss_)+    ss_+    optional $ char ',' >> ss_+    char ']'+    return $ ListExpression items++alistExpression :: Parser Expression+alistExpression = do+    char '{'+    ss_+    items <- option [] $ try $ manySepBy elem $ char ','+    ss_+    optional $ char ',' >> ss_+    char '}'+    return $ AListExpression items+    where+        elem :: Parser (Expression, Expression)+        elem = do+            ss_+            key <- expression+            ss_ >> char ':' >> ss_+            value <- expression+            ss_+            return (key, value)++intLiteral :: Parser Expression+intLiteral = do+    sign <- option '+' $ oneOf "+-"+    str <- many1 digit+    let str' = if sign == '-' then sign:str else str+    return . IntLiteral . read $ str'++floatLiteral :: Parser Expression+floatLiteral = do+    str <- (try dpd <|> try pd)+    return . FloatLiteral . read $ str+    where+        dpd = do+            sign <- option '+' $ oneOf "+-"+            intpart <- many1 digit+            char '.'+            fracpart <- many digit+            let str = intpart ++ "." ++ fracpart+            return $ if sign == '-' then sign:str else str+        pd = do+            sign <- option '+' $ oneOf "+-"+            char '.'+            fracpart <- many1 digit+            let str = "0." ++ fracpart+            return $ if sign == '-' then sign:str else str++stringLiteral :: Parser Expression+stringLiteral = do+    str <- anyQuotedString+    return . StringLiteral $ str++varRefExpr :: Parser Expression+varRefExpr = do+    id <- (string "." <|> identifier)+    return $ VariableReference id++
+ Text/HPaco/Readers/Paco/ParserInternals.hs view
@@ -0,0 +1,67 @@+{-#LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}+module Text.HPaco.Readers.Paco.ParserInternals +    ( PacoState (..)+    , defaultPacoState+    , Text.Parsec.Error.ParseError+    , Parser+    , addDef, resolveDef+    , fillExtension+    )+where++import Control.Exception (Exception)+import Control.Monad+import Control.Monad.IO.Class+import Data.Typeable+import Text.HPaco.Reader+import Text.HPaco.AST.AST+import Text.HPaco.AST.Expression+import Text.HPaco.AST.Statement+import Text.Parsec.Error (ParseError)+import Text.Parsec.Prim+import Text.Parsec.Char+import Text.Parsec.String hiding (Parser)+import System.FilePath++instance Exception ParseError+deriving instance Typeable ParseError++data PacoState = PacoState+                    { psBasePath :: FilePath+                    , psDefs :: [(String, Statement)]+                    , psDeps :: [String]+                    , psIncludeExtension :: Maybe String+                    , psHandleInclude :: Reader+                    }++type Parser a = ParsecT String PacoState IO a++defaultPacoState :: PacoState+defaultPacoState = PacoState+                        { psBasePath = ""+                        , psDefs = []+                        , psDeps = []+                        , psIncludeExtension = Nothing+                        , psHandleInclude = (\s t -> return defAST)+                        }++addDef :: String -> Statement -> Parser ()+addDef name value =+    modifyState (\s -> s { psDefs = ((name, value):psDefs s) })++resolveDef :: String -> Parser Statement+resolveDef name = do+    defs <- psDefs `liftM` getState+    let val = lookup name defs+    maybe+        (unexpected $ name ++ " is not defined.")+        return+        val++fillExtension :: FilePath -> String -> FilePath+fillExtension fp ext =+    let ext0 = takeExtension fp+    in if null ext0+        then replaceExtension fp ext+        else fp+
+ Text/HPaco/Readers/Paco/Statements.hs view
@@ -0,0 +1,235 @@+module Text.HPaco.Readers.Paco.Statements+    ( statements, statement+    )+where++import Control.Monad+import Control.Monad.IO.Class+import System.IO.Strict+import System.FilePath+import System.IO (withFile, IOMode (ReadMode))+import Text.HPaco.Readers.Paco.Basics+import Text.HPaco.Readers.Paco.ParserInternals+import Text.HPaco.Readers.Paco.Expressions+import Text.HPaco.AST.AST+import Text.HPaco.AST.Statement+import Text.HPaco.AST.Expression+import Text.Parsec.Pos (SourcePos, sourceLine, sourceColumn, sourceName)++statements :: Parser [Statement]+statements =+    concat `liftM` many statementPair+    where statementPair = do+                l <- lineNumberStatement+                s <- statement+                return [l,s]++statement :: Parser Statement+statement = try ifStatement +          <|> try withStatement+          <|> try switchStatement+          <|> try forStatement+          <|> try defStatement+          <|> try callStatement+          <|> try commentStatement+          <|> try includeStatement+          <|> try interpolateStatement+          <|> try newlineStatement+          <|> try escapeSequenceStatement+          <|> try rawTextStatement++lineNumberStatement :: Parser Statement+lineNumberStatement = do+    pos <- getPosition+    return $ SourcePositionStatement (sourceName pos) (sourceLine pos)++commentStatement :: Parser Statement+commentStatement = do+    string "{%--"+    manyTill+        (try (discard commentStatement) <|> discard anyChar)+        (try $ string "--%}")+    return NullStatement++includeStatement :: Parser Statement+includeStatement = do+    (basename, innerContext) <- complexTag "include" inner+    dirname <- psBasePath `liftM` getState+    extension <- psIncludeExtension `liftM` getState+    reader <- psHandleInclude `liftM` getState+    let fn0 = joinPath [ dirname, basename ]+    let fn = maybe fn0 (fillExtension fn0) extension+    src <- liftIO $ withFile fn ReadMode hGetContents+    subAst <- liftIO $ reader fn src+    let stmt = astRootStatement subAst+    modifyState (\s -> s { psDeps = fn:psDeps s ++ astDeps subAst })+    return $ maybe stmt (\(ident, expr) -> LetStatement ident expr stmt) innerContext+    where+        path :: Parser String+        path = many1 $ try $ noneOf " \t\r\n%"++        inner :: Parser (String, Maybe (String, Expression))+        inner = do+            basename <- path+            ss_+            innerContext <- optionMaybe $ try (ss_ >> string "with" >> ss_ >> letPair)+            return (basename, innerContext)++interpolateStatement :: Parser Statement+interpolateStatement = do+    char '{'+    em <- option (Just EscapeHTML) escapeMode+    ss_+    expr <- expression+    ss_+    char '}'+    let expr' = maybe+                    expr+                    (\m -> EscapeExpression m expr)+                    em+    return $ PrintStatement $ expr'++rawTextStatement :: Parser Statement+rawTextStatement = do+    chrs <- many1 $ noneOf "{\\\n"+    return $ PrintStatement $ StringLiteral chrs++newlineStatement :: Parser Statement+newlineStatement = do+    char '\n'+    ss_+    return $ PrintStatement $ StringLiteral "\n"++escapeSequenceStatement :: Parser Statement+escapeSequenceStatement = do+    char '\\'+    c <- anyChar+    case c of+        '\n' -> return NullStatement+        otherwise -> return $ PrintStatement $ StringLiteral [ '\\', c ]++ifStatement :: Parser Statement+ifStatement = do+        cond <- complexTag "if" expression+        trueStmts <- statements+        let trueBranch = StatementSequence trueStmts+        falseBranch <- option NullStatement $ try elseBranch+        simpleTag "endif"+        return $ IfStatement cond trueBranch falseBranch+        where elseBranch =+                do+                    simpleTag "else"+                    stmts <- statements+                    return . StatementSequence $ stmts++withStatement :: Parser Statement+withStatement = withOrForStatement (\(n,v) -> LetStatement n v) "with" letPairs++forStatement :: Parser Statement+forStatement = withOrForStatement (\(k, n, v) -> ForStatement k n v) "for" forDefs++withOrForStatement :: (a -> Statement -> Statement) -> String -> Parser [a] -> Parser Statement+withOrForStatement ctor keyword innerP = do+    lets <- complexTag keyword innerP+    stmts <- statements+    simpleTag $ "end" ++ keyword+    return $ foldr ctor (StatementSequence stmts) lets++letPairs :: Parser [(String, Expression)]+letPairs = manySepBy (try letPair) (try $ char ',')++forDefs :: Parser [(Maybe String, String, Expression)]+forDefs = manySepBy (try forDef) (try $ char ',')++letPair :: Parser (String, Expression)+letPair = do+    ss_+    expr <- expression+    ss_+    ident <- option "." $ try $ char ':' >> ss_ >> identifier+    ss_+    return (ident, expr)++forDef :: Parser (Maybe String, String, Expression)+forDef = try forTriple <|> forPair++forPair :: Parser (Maybe String, String, Expression)+forPair = do+    (ident, expr) <- letPair+    return (Nothing, ident, expr)++forTriple :: Parser (Maybe String, String, Expression)+forTriple = do+    ss_+    expr <- expression+    ss_+    char ':'+    ss_+    key <- identifier+    ss_+    doFlip <- option False $ flip+    ss_+    val <- identifier+    ss_+    if doFlip+        then return (Just val, key, expr)+        else return (Just key, val, expr)+    where+        flip = try fwdArr <|> try revArr+        fwdArr = string "->" >> return False+        revArr = string "<-" >> return True++switchStatement :: Parser Statement+switchStatement = do+    masterExpr <- complexTag "switch" expression+    ss_+    branches <- many switchBranch+    ss_+    simpleTag "endswitch"+    return $ SwitchStatement masterExpr branches+    where switchBranch = do+            ss_+            switchExpr <- complexTag "case" expression+            stmts <- statements+            simpleTag "endcase"+            ss_+            return (switchExpr, StatementSequence stmts)++defStatement :: Parser Statement+defStatement = do+    name <- complexTag "def" identifier+    body <- statements+    simpleTag "enddef"+    addDef name $ StatementSequence body+    return NullStatement++callStatement :: Parser Statement+callStatement = do+    name <- complexTag "call" identifier+    optional $ char '\n'+    return $ CallStatement name++simpleTag tag = complexTag tag (return ())+complexTag tag inner = +    let go = do+            string "{%" +            ss_ +            string tag +            ss_ +            i <- inner+            ss_+            string "%}" +            return i+        standalone = do+            assertStartOfLine+            ss_+            v <- go+            char '\n'+            return v++    in try standalone <|> try go++escapeMode :: Parser (Maybe EscapeMode)+escapeMode = (char '!' >> return Nothing)+          <|> (char '@' >> return (Just EscapeURL))+
+ Text/HPaco/Writers/Dependencies.hs view
@@ -0,0 +1,8 @@+module Text.HPaco.Writers.Dependencies ( writeDependencies ) where++import Text.HPaco.AST.AST+import Data.List++writeDependencies :: String -> AST -> String+writeDependencies fn ast =+    fn ++ ": " ++ (concat $ intersperse " " (astDeps ast)) ++ "\n"
Text/HPaco/Writers/Internal/WrapMode.hs view
@@ -4,3 +4,4 @@ where  data WrapMode = WrapNone | WrapFunction | WrapClass+    deriving (Eq)
Text/HPaco/Writers/Javascript.hs view
@@ -47,10 +47,7 @@ defaultJavascriptWriterState =     JavascriptWriterState         { jwsIndent = 0-        , jwsAST = AST-                     { astRootStatement = NullStatement-                     , astDefs = []-                     }+        , jwsAST = defAST         }  type PWS = RWS WriterOptions String JavascriptWriterState@@ -63,9 +60,17 @@ writeAST :: AST -> PWS () writeAST ast = do     writeHeader+    writeDefs $ astDefs ast     writeStatement $ astRootStatement ast     writeFooter +writeDefs = mapM_ writeDef++writeDef (identifier, body) = do+    writeIndentedLn $ "var _macro_" ++ identifier ++ " = function() {"+    withIndent $ writeStatement body+    writeIndentedLn "};"+ write :: String -> PWS () write = tell @@ -156,12 +161,22 @@         NullStatement -> return ()         IfStatement { } -> writeIf stmt         LetStatement identifier expr stmt -> writeLet identifier expr stmt-        ForStatement identifier expr stmt -> writeFor identifier expr stmt+        ForStatement Nothing identifier expr stmt -> writeFor identifier expr stmt+        ForStatement (Just iter) identifier expr stmt -> writeForExt iter identifier expr stmt         SwitchStatement masterExpr branches -> writeSwitch masterExpr branches         CallStatement identifier -> do-            ast <- gets jwsAST-            let body = fromMaybe NullStatement $ lookup identifier $ astDefs ast-            writeStatement body+            -- ast <- gets jwsAST+            -- let body = fromMaybe NullStatement $ lookup identifier $ astDefs ast+            -- writeStatement body+            writeIndentedLn $ "_macro_" ++ identifier ++ ".apply(this);"+        SourcePositionStatement fn ln -> do+            writeIndent+            write "/* "+            write fn+            write ":"+            write $ show ln+            write " */"+            writeNewline  writeIf :: Statement -> PWS () writeIf (IfStatement cond true false) = do@@ -180,41 +195,68 @@                 writeIndentedLn "}"  writeLet :: String -> Expression -> Statement -> PWS ()-writeLet identifier expr stmt = do-    writeWithScope identifier (writeExpression expr) stmt+writeLet identifier expr stmt =+    writeWithScope identifier (writeExpression expr) (writeStatement stmt)   writeFor :: String -> Expression -> Statement -> PWS ()-writeFor identifier expr stmt = do-    writeIndent-    write "_iteree = "-    writeExpression expr-    write ";"-    writeNewline-    writeIndentedLn "for (_index in _iteree) {"-    withIndent $ writeWithScope identifier (write "_iteree[_index]") stmt-    writeIndentedLn "}"+writeFor identifier expr stmt =+    writeFor_ identifier expr $+            withIndent $+            writeWithScope identifier (write "_iteree[_index]") (writeStatement stmt) -writeWithScope :: String -> (PWS ()) -> Statement -> PWS ()-writeWithScope identifier rhs stmt = do+writeForExt :: String -> String -> Expression -> Statement -> PWS ()+writeForExt ident identifier expr stmt =+    writeFor_ identifier expr $+            withIndent $+            writeWithScope ident (write "_index") $+            writeWithScope identifier (write "_iteree[_index]") (writeStatement stmt)++writeFor_ :: String -> Expression -> PWS () -> PWS ()+writeFor_ identifier expr writeInner = do+    writeIndentedLn "(function(){"+    withIndent $ do+        writeIndent+        write "var _iteree = "+        writeExpression expr+        write ";"+        writeNewline+        writeIndentedLn "if (Array.isArray(_iteree)) {"+        withIndent $ do+            writeIndentedLn "for (var _index = 0; _index < _iteree.length; ++_index) {"+            writeInner+            writeIndentedLn "}"+        writeIndentedLn "}"+        writeIndentedLn "else {"+        withIndent $ do+            writeIndentedLn "for (var _index in _iteree) {"+            writeInner+            writeIndentedLn "}"+        writeIndentedLn "}"+    writeIndentedLn "}).apply(this);"++writeWithScope :: String -> (PWS ()) -> (PWS ()) -> PWS ()+writeWithScope identifier rhs inner = do     if identifier == "."         then do             writeIndent-            write "_scope = "+            write "_newscope = "             rhs             write ";"             writeNewline         else do             writeIndent-            write "_scope = {'"+            write "_newscope = {'"             write identifier             write "':"             rhs             write "};"             writeNewline-    writeIndentedLn "_scope.prototype = this;"+    writeIndentedLn "_scope = _merge(this, _newscope);"     writeIndentedLn "(function(){"-    withIndent $ writeStatement stmt+    withIndent $ do+        writeIndentedLn "var _scope = null; var _newscope = null;"+        inner     writeIndentedLn "}).apply(_scope);"  writeSwitch :: Expression -> [(Expression, Statement)] -> PWS ()@@ -242,7 +284,7 @@ writeExpression :: Expression -> PWS () writeExpression expr =     case expr of-        StringLiteral str -> write $ singleQuoteString str+        StringLiteral str -> write $ quoteJavascriptString str          IntLiteral i -> write $ show i         FloatLiteral i -> write $ show i@@ -370,8 +412,8 @@             write "))"  -singleQuoteString :: String -> String-singleQuoteString str =+quoteJavascriptString :: String -> String+quoteJavascriptString str =     "'" ++ escape str ++ "'"     where         escapeChar '\'' = "\\'"
+ Text/HPaco/Writers/JsonLisp.hs view
@@ -0,0 +1,164 @@+{-#LANGUAGE TypeSynonymInstances, FlexibleInstances #-}+module Text.HPaco.Writers.JsonLisp+( writeJsonLisp+)+where++import Control.Monad.RWS+import Text.HPaco.AST.AST+import Text.HPaco.AST.Expression+import Text.HPaco.AST.Statement+import Text.HPaco.Writer+import Data.List+import Data.Maybe++-- Stubbing these types for now; we might need them later.+data JsonLispWriterState =+    JsonLispWriterState { jwsAST :: AST+                        }+data WriterOptions = WriterOptions++type JWS = RWS WriterOptions String JsonLispWriterState++writeJsonLisp :: Writer+writeJsonLisp ast =+    let (s, w) = execRWS (write ast) WriterOptions (JsonLispWriterState ast)+    in w++class JWSWrite a where+    write :: a -> JWS ()++instance JWSWrite (JWS ()) where+    write = id++instance JWSWrite String where+    write = tell++instance JWSWrite Statement where+    write = writeStatement++instance JWSWrite Expression where+    write = writeExpression++instance JWSWrite AST where+    write = writeAST++writeIndent :: JWS ()+writeIndent = return ()++wrapList :: JWS a -> JWS a+wrapList inner = do+    write "["+    x <- inner+    write "]"+    return x++writeList :: [JWS ()] -> JWS ()+writeList ws = do+    wrapList $ sequence_ $ intersperse (write ", ") ws++writes :: JWSWrite a => [a] -> JWS ()+writes = writeList . map write++writeWithHead :: JWSWrite b => String -> [b] -> JWS ()+writeWithHead h xs = writeList ((writeExpression $ StringLiteral h):map write xs)++cullStatements stmts =+    catMaybes $ map toMay stmts+    where+        toMay NullStatement = Nothing+        toMay (SourcePositionStatement {}) = Nothing+        toMay x = Just x++writeAST :: AST -> JWS ()+writeAST ast = do+    writeWithHead "progn" (map writeDef (astDefs ast) ++ [ write $ astRootStatement ast ])++writeDef :: (String, Statement) -> JWS ()+writeDef (defName, stmt) = do+    writeWithHead "def" [ write $ StringLiteral defName, write stmt ]+    +writeStatement :: Statement -> JWS ()+writeStatement stmt = do+    writeIndent+    case stmt of+        StatementSequence ss -> writeWithHead "do" $ cullStatements ss+        PrintStatement expr -> writeWithHead "print" [expr]+            -- case expr of+            --     EscapeExpression _ _ -> writeWithHead "print" [expr]+            --     StringLiteral _ -> writeWithHead "print" [expr]+            --     IntLiteral _ -> writeWithHead "print" [expr]+            --     FloatLiteral _ -> writeWithHead "print" [expr]+            --     otherwise -> wrapList $ write "flatten " >> writeWithHead "print" [expr]+        NullStatement -> return ()+        IfStatement expr true false -> writeList [ (write $ StringLiteral "if"), write expr, write true, write false ]+        LetStatement identifier expr stmt -> writeList [ (write $ StringLiteral "let"), write $ StringLiteral identifier, write expr, write stmt ]+        ForStatement iter identifier expr stmt -> writeList [ (write $ StringLiteral "let"), write $ StringLiteral identifier, write expr, write stmt ]+        SwitchStatement masterExpr branches -> writeWithHead "switch" (map writeSwitchBranch branches)+        CallStatement identifier -> do+            writeWithHead "calldef" [StringLiteral identifier]+            -- ast <- gets jwsAST+            -- let body = fromMaybe NullStatement $ lookup identifier $ astDefs ast+            -- writeStatement body+        SourcePositionStatement fn ln -> return ()+        where+            writeSwitchBranch (expr, stmt) = writeWithHead "case" [ write expr, write stmt ]++writeExpression :: Expression -> JWS ()+writeExpression expr =+    case expr of+        StringLiteral str -> write (quoteString str)+        IntLiteral i -> write (show i)+        FloatLiteral f -> write (show f)+        BooleanLiteral True -> write "true"+        BooleanLiteral False -> write "false"+        VariableReference x -> writeWithHead "getval" [StringLiteral x]+        ListExpression xs -> writeWithHead "list" xs+        AListExpression xs -> writeWithHead "alist" $ map writePair xs+        EscapeExpression EscapeHTML x -> writeWithHead "html" [x]+        EscapeExpression EscapeURL x -> writeWithHead "urlencode" [x]+        FunctionCallExpression fn args -> writeWithHead "call" (fn:args)+        BinaryExpression (Flipped op) lhs rhs -> writeExpression $ BinaryExpression op rhs lhs+        BinaryExpression op lhs rhs ->+            let optk = (binaryOperatorToken op) in+            case op of+                OpMember ->+                    writeWithHead optk [ rhs, lhs ]+                otherwise ->+                    writeWithHead optk [ lhs, rhs ]+        UnaryExpression op lhs -> writeWithHead (unaryOperatorToken op) [ lhs ]+        where+            writePair (a, b) = writeWithHead "pair" [a, b]+            binaryOperatorToken :: BinaryOperator -> String+            binaryOperatorToken OpEquals = "eq"+            binaryOperatorToken OpNotEquals = "neq"+            binaryOperatorToken OpLooseEquals = "eq~"+            binaryOperatorToken OpLooseNotEquals = "neq~"+            binaryOperatorToken OpGreater = "gt"+            binaryOperatorToken OpLess = "lt"+            binaryOperatorToken OpNotGreater = "lte"+            binaryOperatorToken OpNotLess = "gte"+            binaryOperatorToken OpPlus = "add"+            binaryOperatorToken OpMinus = "sub"+            binaryOperatorToken OpMul = "mul"+            binaryOperatorToken OpDiv = "div"+            binaryOperatorToken OpMod = "mod"+            binaryOperatorToken OpMember = "getval"+            binaryOperatorToken OpBooleanAnd = "and"+            binaryOperatorToken OpBooleanOr = "or"+            binaryOperatorToken OpBooleanXor = "xor"+            binaryOperatorToken OpInList = "in"+            unaryOperatorToken :: UnaryOperator -> String+            unaryOperatorToken OpNot = "not"+++quoteString :: String -> String+quoteString str =+    "\"" ++ escape str ++ "\""+    where+        escapeChar '\"' = "\\\""+        escapeChar '\n' = "\\n"+        escapeChar '\t' = "\\t"+        escapeChar '\r' = "\\r"+        escapeChar x = [x]+        escape = concat . map escapeChar
Text/HPaco/Writers/PHP.hs view
@@ -12,6 +12,7 @@ import Data.List (intersperse) import Data.Maybe import Data.Typeable+import Data.Char import Text.HPaco.AST.AST import Text.HPaco.AST.Expression import Text.HPaco.AST.Statement@@ -40,23 +41,24 @@  data OutputMode = PHP | Html +type ScopeMap = [M.Map String String]+ data PHPWriterState =     PHPWriterState { pwsIndent :: Int-                   , pwsLocalScope :: [M.Map String Integer]+                   , pwsLocalScope :: ScopeMap                    , pwsNextLocalVariableID :: Integer                    , pwsAST :: AST                    , pwsOutputMode :: OutputMode+                   , pwsEscapeFilter :: String -> String                    }  defaultPHPWriterState =     PHPWriterState { pwsIndent = 0                    , pwsLocalScope = []                    , pwsNextLocalVariableID = 0-                   , pwsAST = AST-                                { astRootStatement = NullStatement-                                , astDefs = []-                                }+                   , pwsAST = defAST                    , pwsOutputMode = Html+                   , pwsEscapeFilter = id                    }  type PWS = RWS WriterOptions String PHPWriterState@@ -69,12 +71,23 @@ writeAST :: AST -> PWS () writeAST ast = do     writeHeader+    writeDefs $ astDefs ast     writeStatement $ astRootStatement ast     writeFooter  write :: String -> PWS ()-write = tell+write str = do+    f <- gets pwsEscapeFilter+    tell $ f str +withFilter :: (String -> String) -> PWS a -> PWS a+withFilter f ac = do+    f0 <- gets pwsEscapeFilter+    modify (\s -> s { pwsEscapeFilter = f0 . f })+    r <- ac+    modify (\s -> s { pwsEscapeFilter = f0 })+    return r+ getOutputMode :: PWS OutputMode getOutputMode = gets pwsOutputMode @@ -83,7 +96,7 @@     m0 <- getOutputMode     modify (\s -> s { pwsOutputMode = m })     case (m0, m) of-        (Html, PHP) -> write "<?php" >> writeNewline+        (Html, PHP) -> write "<?php "         (PHP, Html) -> write "?>"         otherwise -> return () @@ -99,7 +112,14 @@ popScope :: PWS () popScope = modify (\s -> s { pwsLocalScope = tail (pwsLocalScope s) }) -scopeResolve :: String -> PWS (Maybe Integer)+getScope :: PWS ScopeMap+getScope = gets pwsLocalScope++setScope :: ScopeMap -> PWS ()+setScope newScope = modify (\s -> s { pwsLocalScope = newScope })+++scopeResolve :: String -> PWS (Maybe String) scopeResolve key = do     scopeStack <- gets pwsLocalScope     return $ resolve key scopeStack@@ -124,17 +144,28 @@     modify (\s -> s { pwsNextLocalVariableID = 1 + pwsNextLocalVariableID s })     return id -toVarname :: Integer -> String-toVarname i = "_lv" ++ show i+toVarname :: String -> String+toVarname i = "_lv" ++ i -defineVariable :: String -> PWS Integer+defineVariable :: String -> PWS String defineVariable key = do-    vid <- nextVarID+    vidInt <- nextVarID+    let vid = show vidInt ++ "_" ++ sanitizeIdentifier key     scope <- gets pwsLocalScope >>= \x -> return $ head x     let scope' =  M.insert key vid . M.delete key $ scope     modify (\s -> s { pwsLocalScope = scope':tail (pwsLocalScope s) })     return vid +-- Filter an arbitrary string to become a valid PHP identifier tail+sanitizeIdentifier :: String -> String+sanitizeIdentifier str =+    map sanitizeIdentifierChar str+    where+        sanitizeIdentifierChar c =+            if isAlphaNum c+                then c+                else '_'+ withIndent :: PWS a -> PWS a withIndent a = do     pushIndent@@ -169,7 +200,6 @@     let src = BS8.unpack $(embedFile "snippets/php/preamble.php")     setOutputMode Html     write src-    writeNewline  writeHeader :: PWS () writeHeader = do@@ -177,10 +207,10 @@     includePreamble <- woIncludePreamble `liftM` ask     wrapMode <- woWrapMode `liftM` ask -    setOutputMode PHP-     when includePreamble writePreamble +    setOutputMode PHP+     case wrapMode of         WrapFunction -> do             let funcName =@@ -220,10 +250,41 @@     writeIndentedLn "$_scope = array();"     writePushScope -writePushScope = do-    vid <- resolveVariable "."-    writeIndentedLn $ "$_scope = new _S($" ++ vid ++ ", $_scope);"+writeDefs defs = do+    mapM_ writeDef defs +withSealedScope inner = do+    outerScope <- getScope+    setScope []+    result <- inner+    setScope outerScope+    return result++writeDef (ident, stmt) = do+    setOutputMode PHP+    wrapMode <- woWrapMode `liftM` ask+    writeIndent+    case wrapMode of+        WrapClass -> write "private static $_macro_"+        otherwise -> write "$_macro_"+    write ident+    write " = '"+    writeNewline+    withFilter evalQuoteString $ withIndent $ writeStatement stmt+    setOutputMode PHP+    writeIndentedLn "';"++writePushScope = writePushScopeVar "."++writePushScopeVar var = do+    vid <- resolveVariable var+    let str = if var == "."+                then+                    "$_scope = new _S($" ++ vid ++ ", $_scope);"+                else+                    "$_scope = new _S(array('" ++ var ++ "' => $" ++ vid ++ "), $_scope);"+    writeIndentedLn str+ writePopScope =     writeIndentedLn "if ($_scope instanceof _S) { $_scope = $_scope->p; } else { $_scope = array(); }" @@ -265,12 +326,25 @@         NullStatement -> return ()         IfStatement { } -> writeIf stmt         LetStatement identifier expr stmt -> writeLet identifier expr stmt-        ForStatement identifier expr stmt -> writeFor identifier expr stmt+        ForStatement iter identifier expr stmt -> writeFor iter identifier expr stmt         SwitchStatement masterExpr branches -> writeSwitch masterExpr branches         CallStatement identifier -> do-            ast <- gets pwsAST-            let body = fromMaybe NullStatement $ lookup identifier $ astDefs ast-            writeStatement body+            wrapMode <- woWrapMode `liftM` ask+            writeIndent+            write "eval("+            when (wrapMode == WrapClass) $ write "self::"+            write "$_macro_"+            write identifier+            write ");"+            writeNewline+        SourcePositionStatement fn ln -> do+            writeIndent+            write "/* "+            write fn+            write ":"+            write $ show ln+            write " */"+            writeNewline  writeIf :: Statement -> PWS () writeIf (IfStatement cond true false) = do@@ -290,23 +364,18 @@  writeLet :: String -> Expression -> Statement -> PWS () writeLet identifier expr stmt = do-    writeIndent-    write "$_tmp = "-    writeExpression expr-    write ";"-    writeNewline     pushScope     id <- defineVariable identifier      writeIndent     write "$"     write $ toVarname id-    write " = $_tmp;"+    write " = "+    writeExpression expr+    write ";"     writeNewline -    if identifier == "."-        then writePushScope-        else return ()+    writePushScopeVar identifier      writeStatement stmt @@ -317,13 +386,11 @@     writeNewline      popScope-    if identifier == "."-        then writePopScope-        else return ()+    writePopScope  -writeFor :: String -> Expression -> Statement -> PWS ()-writeFor identifier expr stmt = do+writeFor :: Maybe String -> String -> Expression -> Statement -> PWS ()+writeFor iter identifier expr stmt = do     pushScope     id <- defineVariable identifier @@ -338,16 +405,20 @@     withIndent $ do         writeIndent         write "foreach ($_iteree as $"+        case iter of+            Just k -> do+                kid <- defineVariable k+                write $ toVarname kid+                write " => $"+            otherwise -> return ()         write $ toVarname id         write ") {"         writeNewline          withIndent $ do-            when (identifier == ".")-                writePushScope+            writePushScopeVar identifier             writeStatement stmt-            when (identifier == ".")-                writePushScope+            writePopScope          writeIndentedLn "}" @@ -416,7 +487,7 @@             vid <- maybeResolveVariable vn             write $ maybe                 ("_r($_scope, '" ++ vn ++ "')")-                (\v -> "(isset($" ++ v ++ ") ? $" ++ v ++ " : null)")+                (\v -> "(isset($" ++ v ++ ") ? $" ++ v ++ " : _r($_scope, '" ++ vn ++ "'))")                 vid          EscapeExpression mode e -> do@@ -498,3 +569,10 @@         escapeChar '$' = "\\$"         escapeChar x = [x]         escape = concat . map escapeChar++evalQuoteString :: String -> String+evalQuoteString =+    concat . map escapeChar+    where+        escapeChar '\'' = "\\\'"+        escapeChar x = [x]
Text/HPaco/Writers/Run.hs view
@@ -15,9 +15,11 @@ import qualified Data.Variant as V import Data.Maybe import qualified Data.List as List+import qualified Data.List.Split as Split import Control.Monad.State import Safe import Text.HPaco.Writers.Run.Encode+import Text.HPaco.Writers.Run.Library import Text.HPaco.AST import Text.HPaco.AST.AST import Text.HPaco.AST.Statement@@ -65,9 +67,12 @@     runStatement $ if b then true else false runStatement (LetStatement ident expr stmt) =     runExpression expr >>= \e -> withIdentifiedScope ident e (runStatement stmt)-runStatement (ForStatement ident expr stmt) = do+runStatement (ForStatement Nothing ident expr stmt) = do     es <- runExpression expr     sequence_ $ vmap (\e -> withIdentifiedScope ident e (runStatement stmt)) es+runStatement (ForStatement (Just iter) ident expr stmt) = do+    es <- runExpression expr+    sequence_ $ vamap (\(k, v) -> withIdentifiedScope iter k $ withIdentifiedScope ident v (runStatement stmt)) es runStatement (SwitchStatement expr branches) = do     ev <- runExpression expr     tests <- mapM runExpression $ map fst branches@@ -79,6 +84,7 @@     ast <- gets rsAST     let body = fromMaybe NullStatement $ List.lookup identifier $ astDefs ast     runStatement body+runStatement SourcePositionStatement {} = return ()  -- Scope helpers @@ -133,19 +139,11 @@ runExpression (VariableReference varname) = getVar varname runExpression (FunctionCallExpression (VariableReference "library") (libnameExpr:_)) = do     libname <- runExpression libnameExpr-    loadLibrary $ V.flatten libname+    return $ loadLibrary $ V.flatten libname runExpression (FunctionCallExpression fn argExprs) = do     func <- runExpression fn     args <- mapM runExpression argExprs     return $ V.call func args--loadLibrary :: String -> Run Variant-loadLibrary "std" =-    return $-        AList [ ( String "count", wrapf1 (Integer . fromIntegral . List.length . V.toAList) )-              , ( String "join", wrapf (\(sep:lst:_) -> String . List.concat . List.intersperse (V.flatten sep) . map V.flatten . V.values $ lst) )-              ]-loadLibrary other = return Null  applyBinaryOperation :: BinaryOperator -> Variant -> Variant -> Variant applyBinaryOperation OpPlus = (+)
+ Text/HPaco/Writers/Run/Library.hs view
@@ -0,0 +1,50 @@+module Text.HPaco.Writers.Run.Library+    ( loadLibrary+    )+where++import Data.Variant as V+import Data.Variant.ToFrom+import qualified Data.List.Split as Split+import Data.List as List+import Data.Tuple (swap)++join :: String -> [String] -> String+join sep lst = List.concat $ List.intersperse sep lst++split :: String -> String -> [String]+split sep str = Split.splitOn sep str++map_ :: [Variant] -> Variant+map_ (fv:xsv:_) =+    let f = case fv of+                Function ff -> (\a -> ff [a])+                otherwise -> id+        xs = V.values xsv+        ks = V.keys xsv+    in AList $ zip ks $ map f xs+map_ _ = V.Null++zip_ :: [Variant] -> Variant+zip_ (k:v:_) =+    let ka = values k+        kv = values v+    in AList $ zip ka kv+zip_ _ = V.Null++loadLibrary :: String -> Variant+loadLibrary "list" =+        AList [ ( String "count", Function (toVariant . length . toAList . head) )+              , ( String "sort", Function (toVariant . map swap . List.sort . map swap . toAList . head) )+              , ( String "zip", Function zip_ )+              ]+loadLibrary "string" =+        AList [ ( String "join", toVariant join )+              , ( String "split", toVariant split )+              ]+loadLibrary "std" =+        V.merge (loadLibrary "list") (loadLibrary "string")+loadLibrary "fp" =+        AList [ ( String "map", Function map_ )+              ]+loadLibrary other = Null
hpaco-lib.cabal view
@@ -1,5 +1,5 @@ name:                hpaco-lib-version:             0.11.0.6+version:             0.16.1.0 synopsis:            Modular template compiler library description:         Template compiler library, compiles template code into                      PHP or Javascript, or interprets it directly.@@ -20,11 +20,18 @@ library   exposed-modules: Text.HPaco.Optimizer                  , Text.HPaco.Readers.Paco+                 , Text.HPaco.Readers.Paco.ParserInternals+                 , Text.HPaco.Readers.Paco.Basics+                 , Text.HPaco.Readers.Paco.Expressions+                 , Text.HPaco.Readers.Paco.Statements                  , Text.HPaco.Writers.Javascript+                 , Text.HPaco.Writers.JsonLisp+                 , Text.HPaco.Writers.Dependencies                  , Text.HPaco.Writers.Run                  , Text.HPaco.Writers.PHP                  , Text.HPaco.Writers.Internal.WrapMode                  , Text.HPaco.Writers.Run.Encode+                 , Text.HPaco.Writers.Run.Library                  , Text.HPaco.AST                  , Text.HPaco.AST.Statement                  , Text.HPaco.AST.Identifier@@ -33,6 +40,7 @@                  , Text.HPaco.Writer                  , Text.HPaco.Reader                  , Data.Variant+                 , Data.Variant.ToFrom   -- other-modules:          build-depends:       base == 4.*                ,       bytestring == 0.9.*
snippets/js/preamble.js view
@@ -1,3 +1,20 @@+	var _clone = function (obj){+		if(obj == null || typeof(obj) != 'object')+			return obj;+		var temp = obj.constructor();+		for(var key in obj)+			temp[key] = _clone(obj[key]);+		return temp;+	}+	var _merge = function(p,c) {+		if(c == null || typeof(c) != 'object')+			return c;+		var res = _clone(p);+		for(var key in c)+			res[key] = _clone(c[key]);+		return res;+	}+ 	var _htmlencode = function(str){ 		return String(str) 			.replace(/&/g, '&amp;')@@ -14,6 +31,16 @@ 		} 		return String(str); 	};+	var _a = function(a) {+		if (Array.isArray(a)) return a;+		if (typeof(a) === 'object') {+			var aa = [];+			for (var p in a) {+				aa.push(a[p]);+			}+		}+		return [];+	} 	var _in = function(a,b) { 		if (!Array.isArray(b)){return false;} 		for (var i = 0; i < b.length; ++i) { if (a == b[i]) return true; }@@ -21,10 +48,46 @@ 	}; 	var _loadlib = function (libname) { 		switch (libname) {+			case 'list':+				return {+					'count' : function(a){return _a(a).length;},+					'sort' : function(a){return _a(a).sort();},+					'zip' : function(k,v){+								var ka = _a(k);+								var va = _a(v);+								var o = {};+								for (var i = 0; i < ka.length && i < va.length; ++i) {+									o[ka[i]] = va[i];+								}+								return o;+							}+				};+			case 'string':+				return {+					'join' : function(s,a){return _a(a).join(s);},+					'split' : function(s,a){return _f(a).split(s);}+				}; 			case 'std':+				return _merge(_loadlib('string'), _loadlib('list'));+			case 'fp': 				return {-					'count' : function(a){return a.length;}-,					'join' : function(s,a){return a.join(s);}+					'map' : function(f,a){+						if (Array.isArray(a)) {+							var o = [];+							for (var i = 0; i < a.length; ++i) {+								o.push(f(a[i]));+							}+							return o;+						}+						if (typeof(a) === 'object') {+							var o = {};+							for(p in a) {+								o[p] = f(a[p]);+							}+							return o;+						}+						return null;+					} 				}; 			default: throw new Exception('No such library: ' + libname); 		}
snippets/php/preamble.php view
@@ -28,18 +28,17 @@ 		public function __toString() { return '<<function>>'; } 	} }-if (!class_exists('_LL', false)) {-	class _LL {-		public function __invoke($libname) {-			switch ($libname) {-				case 'std':-					return array(-						'count' => new _LF('count'),-						'join' => new _LF('implode'),-					);-				default: throw new Exception('No such library: ' . $libname);-			}+if (!class_exists('_AF', false)) {+	class _AF {+		public function __isset($key) {+			return is_callable($key); 		}+		public function __get($key) {+			if (is_callable($key))+				return new _LF($key);+			else+				return null;+		} 	} } if (!is_callable('_r')) {@@ -71,6 +70,39 @@ 		return (string)$val; 	} }+if (!class_exists('_LL', false)) {+	class _LL {+		 +		public function __invoke($libname) {+			switch ($libname) {+				case 'std':+					return array_merge($this->__invoke('string'), $this->__invoke('list'));+				case 'list':+					return array(+						'count' => new _LF('count'),+						'sort' => new _LF(function($a){sort($a);return $a;}),+						'zip' => new _LF('array_combine'),+					);+				case 'string':+					return array(+						'join' => new _LF(function($sep,$arr){if(!is_array($arr)) return array();return implode(_f($sep),$arr);}),+						'split' => new _LF(function($sep, $str){return explode(_f($sep),_f($str));}),+					);+				case 'fp':+					return array(+						'map' => new _LF(function($f,$a){+												return array_map(+													function($x) use ($f) {return _call($f,array($x));},+													$a);+											}),+						);+				case 'php.all_functions':+					return new _AF();+				default: throw new Exception('No such library: ' . $libname);+			}+		}+	}+} if (!is_callable('_call')) { 	function _call($func, $args) { 		if ($func instanceof FunctionPointer || $func instanceof _LL || $func instanceof _LF) {@@ -79,3 +111,4 @@ 		return null; 	} }+?>