Changeset 4544

Show
Ignore:
Timestamp:
06/12/05 11:40:31 (4 years ago)
Author:
iblech
svk:copy_cache_prev:
6289
Message:

Macros.
* t/macros/ -- unSKIP and more tests
* Pugs.Eval.Var -- New module containing findVar & co.
* Pugs.Prim.Param -- New module containing foldParam
* Pugs.Prim, Pugs.AST.Internals, Pugs.Eval, Pugs.Prim.List --

Moved several functions to new Pugs.Eval.Var, Pugs.Prim.Param, and
Pugs.Prim.List.

* Pugs.Parser -- Various calls to new fun possiblyApplyMacro.
* Pugs.Parser.Unsafe -- New fun possiblyApplyMacro.

Files:
3 added
8 modified

Legend:

Unmodified
Added
Removed
  • src/Pugs/AST/Internals.hs

    r4440 r4544  
    684684             | SubCoroutine -- ^ Coroutine 
    685685             | SubRoutine   -- ^ Regular subroutine 
     686             | SubMacro     -- ^ Macro 
    686687             | SubBlock     -- ^ Bare block 
    687688             | SubPointy    -- ^ Pointy sub 
  • src/Pugs/Eval.hs

    r4533 r4544  
    3131    enterLValue, enterRValue, 
    3232) where 
    33 import Pugs.Config 
    3433import Pugs.Internals 
    3534import Prelude hiding ( exp ) 
     
    4645import Pugs.Pretty 
    4746import Pugs.Types 
    48 import Pugs.Prim.List (op2Fold) 
    4947import Pugs.External 
    50 import Pugs.Embed.Perl5 
     48import Pugs.Eval.Var 
    5149 
    5250{-| 
     
    132130    trapVal val (return val) 
    133131 
    134 findSyms :: Var -> Eval [(String, Val)] 
    135 findSyms name = do 
    136     lex  <- asks envLexical 
    137     glob <- askGlobal 
    138     pkg  <- asks envPackage 
    139     let names = nub [name, toPackage pkg name, toGlobal name] 
    140     syms <- forM [lex, glob] $ \pad -> do 
    141         forM names $ \name' -> do 
    142             case lookupPad name' pad of 
    143                 Just tvar -> do 
    144                     refs  <- liftSTM $ mapM readTVar tvar 
    145                     forM refs $ \ref -> do 
    146                         val <- readRef ref 
    147                         return (name', val) 
    148                 Nothing -> return [] 
    149     return $ concat (concat syms) 
    150  
    151132-- Reduction --------------------------------------------------------------- 
    152133 
     
    174155    VControl c      -> retControl c 
    175156    _               -> action 
    176  
    177 evalVar :: Var -> Eval Val 
    178 evalVar name = do 
    179     v <- findVar name 
    180     case v of 
    181         Just var -> readRef var 
    182         _ | (':':rest) <- name -> return $ VType (mkType rest) 
    183         _ -> retError "Undeclared variable" name 
    184157 
    185158{-| 
     
    194167enterRValue = local (\e -> e{ envLValue = False }) 
    195168 
    196 findVar :: Var -> Eval (Maybe VRef) 
    197 findVar name = do 
    198     rv <- findVarRef name 
    199     case rv of 
    200         Nothing  -> case name of 
    201             ('&':_) -> maybeM (findSub name Nothing []) $ \sub -> do 
    202                 return $ codeRef sub 
    203             _ -> return Nothing 
    204         Just ref -> fmap Just $ liftSTM (readTVar ref) 
    205  
    206 findVarRef :: Var -> Eval (Maybe (TVar VRef)) 
    207 findVarRef name 
    208     | Just (package, name') <- breakOnGlue "::" name 
    209     , Just (sig, "") <- breakOnGlue "CALLER" package = do 
    210         maybeCaller <- asks envCaller 
    211         case maybeCaller of 
    212             Just env -> local (const env) $ do 
    213                 findVarRef (sig ++ name') 
    214             Nothing -> retError "cannot access CALLER:: in top level" name 
    215     | Just (package, name') <- breakOnGlue "::" name 
    216     , Just (sig, "") <- breakOnGlue "OUTER" package = do 
    217         maybeOuter <- asks envOuter 
    218         case maybeOuter of 
    219             Just env -> local (const env) $ do 
    220                 findVarRef (sig ++ name') 
    221             Nothing -> retError "cannot access OUTER:: in top level" name 
    222     | (_:'?':_) <- name = do 
    223         rv  <- getMagical name 
    224         case rv of 
    225             Nothing  -> doFindVarRef name 
    226             Just val -> do 
    227                 tvar <- liftSTM $ newTVar (MkRef . constScalar $ val) 
    228                 return $ Just tvar 
    229     | "%" <- name = do 
    230         {- %CALLER::, %OUTER::, %Package::, etc, all recurse to here. -} 
    231         pad <- asks envLexical 
    232         let plist   = padToList pad 
    233         hlist <- mapM padEntryToHashEntry plist 
    234         let hash    = IHash $ Map.fromList hlist 
    235         let hashref = MkRef hash 
    236         tvar <- liftSTM $ newTVar hashref 
    237         return $ Just tvar 
    238     | otherwise = doFindVarRef name 
    239     where 
    240     padEntryToHashEntry :: (Var, [(TVar Bool, TVar VRef)]) -> Eval (VStr, Val) 
    241     padEntryToHashEntry (key, (_, tvref) : _) = do 
    242         vref   <- liftSTM (readTVar tvref) 
    243         let val = VRef vref 
    244         return (key, val) 
    245     padEntryToHashEntry (_, []) = do fail "Nonexistant var in pad?" 
    246     doFindVarRef :: Var -> Eval (Maybe (TVar VRef)) 
    247     doFindVarRef name = do 
    248         callCC $ \foundIt -> do 
    249             lexSym <- fmap (findSym name . envLexical) ask 
    250             when (isJust lexSym) $ foundIt lexSym 
    251             glob   <- liftSTM . readTVar . envGlobal =<< ask 
    252             let globSym = findSym name glob 
    253             when (isJust globSym) $ foundIt globSym 
    254             let globSym = findSym (toGlobal name) glob 
    255             when (isJust globSym) $ foundIt globSym 
    256             return Nothing 
    257  
    258 posSym :: Value a => (Pos -> a) -> Eval (Maybe Val) 
    259 posSym f = fmap (Just . castV . f) $ asks envPos 
    260 constSym :: String -> Eval (Maybe Val) 
    261 constSym = return . Just . castV 
    262  
    263 {-| 
    264 Evaluate the \'magical\' variable associated with a given name. Returns  
    265 @Nothing@ if the name does not match a known magical. 
    266 -} 
    267 getMagical :: String -- ^ Name of the magical var to evaluate 
    268            -> Eval (Maybe Val) 
    269 getMagical "$?FILE"     = posSym posName 
    270 getMagical "$?LINE"     = posSym posBeginLine 
    271 getMagical "$?COLUMN"   = posSym posBeginColumn 
    272 getMagical "$?POSITION" = posSym pretty 
    273 getMagical "$?MODULE"   = constSym "main" 
    274 getMagical "$?OS"       = constSym $ getConfig "osname" 
    275 getMagical "$?CLASS"    = fmap (Just . VType . mkType) (asks envPackage) 
    276 getMagical ":?CLASS"    = fmap (Just . VType . mkType) (asks envPackage) 
    277 getMagical "$?PACKAGE"  = fmap (Just . VType . mkType) (asks envPackage) 
    278 getMagical ":?PACKAGE"  = fmap (Just . VType . mkType) (asks envPackage) 
    279 getMagical "$?ROLE"     = fmap (Just . VType . mkType) (asks envPackage) 
    280 getMagical ":?ROLE"     = fmap (Just . VType . mkType) (asks envPackage) 
    281 getMagical _            = return Nothing 
     169 
    282170 
    283171evalRef :: VRef -> Eval Val 
     
    923811        _ -> cxtSlurpyAny 
    924812cxtOfExp _                      = return cxtSlurpyAny 
    925  
    926 findSub :: String     -- ^ Name, with leading @\&@. 
    927         -> Maybe Exp  -- ^ Invocant 
    928         -> [Exp]      -- ^ Other arguments 
    929         -> Eval (Maybe VCode) 
    930 findSub name' invs args = do 
    931     let name = possiblyFixOperatorName name' 
    932     case invs of 
    933         Just _ | Just (package, name') <- breakOnGlue "::" name 
    934                  , Just (sig, "") <- breakOnGlue "SUPER" package -> do 
    935             typ <- asks envPackage 
    936             findSuperSub (mkType typ) (sig ++ name') 
    937         Just exp | not (':' `elem` drop 2 name) -> do 
    938             typ     <- evalInvType $ unwrap exp 
    939             if typ == mkType "Scalar::Perl5" then runPerl5Sub name else do 
    940             findTypedSub typ name 
    941         _ | [exp] <- args -> do 
    942             typ     <- evalInvType $ unwrap exp 
    943             findTypedSub typ name 
    944         _ -> findBuiltinSub name 
    945     where 
    946     findSuperSub :: Type -> String -> Eval (Maybe VCode) 
    947     findSuperSub typ name = do 
    948         let pkg = showType typ 
    949             qualified = (head name:pkg) ++ "::" ++ tail name 
    950         subs    <- findWithSuper pkg name 
    951         subs'   <- if isJust subs then return subs else findBuiltinSub name 
    952         case subs' of 
    953             Just sub | subName sub == qualified -> return Nothing 
    954             _   -> return subs' 
    955     findTypedSub :: Type -> String -> Eval (Maybe VCode) 
    956     findTypedSub typ name = do 
    957         subs    <- findWithPkg (showType typ) name 
    958         if isJust subs then return subs else findBuiltinSub name 
    959     findBuiltinSub :: String -> Eval (Maybe VCode) 
    960     findBuiltinSub name = do 
    961         sub <- findSub' name 
    962         if isNothing sub then possiblyBuildMetaopVCode name else return sub 
    963     evalInvType :: Exp -> Eval Type 
    964     evalInvType x@(Var (':':typ)) = do 
    965         typ' <- evalExpType x 
    966         return $ if typ' == mkType "Scalar::Perl5" then typ' else mkType typ 
    967     evalInvType (App (Var "&new") (Just inv) _) = do 
    968         evalInvType $ unwrap inv 
    969     evalInvType x@(App (Var _) (Just inv) _) = do 
    970         typ <- evalInvType $ unwrap inv 
    971         if typ == mkType "Scalar::Perl5" then return typ else evalExpType x 
    972     evalInvType x = evalExpType $ unwrap x 
    973     runPerl5Sub :: String -> Eval (Maybe VCode) 
    974     runPerl5Sub name = do 
    975         metaSub <- possiblyBuildMetaopVCode name 
    976         if isJust metaSub then return metaSub else do 
    977         return . Just $ mkPrim 
    978             { subName     = name 
    979             , subParams   = makeParams ["Object", "List", "Named"] 
    980             , subReturns  = mkType "Scalar::Perl5" 
    981             , subBody     = Prim $ \(inv:named:pos:_) -> do 
    982                 sv      <- fromVal inv 
    983                 posSVs  <- fromVals pos 
    984                 namSVs  <- fmap concat (fromVals named) 
    985                 let svs = posSVs ++ namSVs 
    986                 found   <- liftIO $ canPerl5 sv (tail name) 
    987                 found'  <- liftIO $ if found 
    988                     then return found 
    989                     else canPerl5 sv "AUTOLOAD" 
    990                 if not found' then evalExp (App (Var name) Nothing (map (Val . PerlSV) (sv:svs))) else do 
    991                 env     <- ask 
    992                 rv      <- liftIO $ do 
    993                     envSV   <- mkVal (VControl $ ControlEnv env) 
    994                     subSV   <- vstrToSV $ tail name 
    995                     invokePerl5 subSV sv svs envSV (enumCxt $ envContext env) 
    996                 return $ case rv of 
    997                     [sv]    -> PerlSV sv 
    998                     _       -> VList (map PerlSV rv) 
    999             } 
    1000     possiblyBuildMetaopVCode :: String -> Eval (Maybe VCode) 
    1001     possiblyBuildMetaopVCode op' | "&prefix:[" `isPrefixOf` op', "]" `isSuffixOf` op' = do  
    1002         -- Strip the trailing "]" from op 
    1003         let op = drop 9 (init op') 
    1004         -- We try to find the userdefined sub. 
    1005         -- We use the first two elements of invs as invocants, as these are the 
    1006         -- types of the op. 
    1007             rv = findSub ("&infix:" ++ op) Nothing (take 2 $ args ++ [Val undef, Val undef]) 
    1008         maybeM rv $ \code -> return $ mkPrim 
    1009             { subName     = "&prefix:[" ++ op ++ "]" 
    1010             , subType     = SubPrim 
    1011             , subAssoc    = "spre" 
    1012             , subParams   = makeParams ["List"] 
    1013             , subReturns  = mkType "Str" 
    1014             , subBody     = Prim $ \[vs] -> do 
    1015                 list_of_args <- fromVal vs 
    1016                 op2Fold (list_of_args) (VCode code) 
    1017             } 
    1018         -- Now we construct the sub. Is there a more simple way to do it? 
    1019     possiblyBuildMetaopVCode op' | "&prefix:" `isPrefixOf` op', "\171" `isSuffixOf` op' = do  
    1020         let op = drop 8 (init op') 
    1021         possiblyBuildMetaopVCode ("&prefix:" ++ op ++ "<<") 
    1022     possiblyBuildMetaopVCode op' | "&prefix:" `isPrefixOf` op', "<<" `isSuffixOf` op' = do  
    1023         let op = drop 8 (init (init op')) 
    1024             rv = findSub ("&prefix:" ++ op) Nothing [head $ args ++ [Val undef]] 
    1025         maybeM rv $ \code -> return $ mkPrim 
    1026             { subName     = "&prefix:" ++ op ++ "<<" 
    1027             , subType     = SubPrim 
    1028             , subAssoc    = subAssoc code 
    1029             , subParams   = subParams code 
    1030             , subReturns  = mkType "List" 
    1031             , subBody     = Prim 
    1032                 (\x -> op1HyperPrefix code (listArg x)) 
    1033             } 
    1034     possiblyBuildMetaopVCode op' | "&postfix:\187" `isPrefixOf` op' = do 
    1035         let op = drop 10 op' 
    1036         possiblyBuildMetaopVCode ("&postfix:>>" ++ op) 
    1037     possiblyBuildMetaopVCode op' | "&postfix:>>" `isPrefixOf` op' = do 
    1038         let op = drop 11 op' 
    1039             rv = findSub ("&postfix:" ++ op) Nothing [head $ args ++ [Val undef]] 
    1040         maybeM rv $ \code -> return $ mkPrim 
    1041             { subName     = "&postfix:>>" ++ op 
    1042             , subType     = SubPrim 
    1043             , subAssoc    = subAssoc code 
    1044             , subParams   = subParams code 
    1045             , subReturns  = mkType "List" 
    1046             , subBody     = Prim 
    1047                 (\x -> op1HyperPostfix code (listArg x)) 
    1048             } 
    1049     possiblyBuildMetaopVCode op' | "&infix:\187" `isPrefixOf` op', "\171" `isSuffixOf` op' = do  
    1050         let op = drop 8 (init op') 
    1051         possiblyBuildMetaopVCode ("&infix:>>" ++ op ++ "<<") 
    1052     possiblyBuildMetaopVCode op' | "&infix:>>" `isPrefixOf` op', "<<" `isSuffixOf` op' = do  
    1053         let op = drop 9 (init (init op')) 
    1054             rv = findSub ("&infix:" ++ op) Nothing (take 2 (args ++ [Val undef, Val undef])) 
    1055         maybeM rv $ \code -> return $ mkPrim 
    1056             { subName     = "&infix:>>" ++ op ++ "<<" 
    1057             , subType     = SubPrim 
    1058             , subAssoc    = subAssoc code 
    1059             , subParams   = makeParams ["Any", "Any"] 
    1060             , subReturns  = mkType "List" 
    1061             , subBody     = Prim (\[x, y] -> op2Hyper code x y) 
    1062             } 
    1063         -- Taken from Pugs.Prim. Probably this should be refactored. (?) 
    1064     possiblyBuildMetaopVCode _ = return Nothing 
    1065     listArg [x] = x 
    1066     listArg xs = VList xs 
    1067     makeParams = map (\p -> p{ isWritable = isLValue p }) . foldr foldParam [] . map takeWord 
    1068     takeWord = takeWhile isWord . dropWhile (not . isWord) 
    1069     isWord   = not . (`elem` "(),:") 
    1070     findAttrs pkg = do 
    1071         maybeM (findVar (':':'*':pkg)) $ \ref -> do 
    1072             meta    <- readRef ref 
    1073             fetch   <- doHash meta hash_fetchVal 
    1074             fromVal =<< fetch "traits" 
    1075     findWithPkg :: String -> String -> Eval (Maybe VCode) 
    1076     findWithPkg pkg name = do 
    1077         subs <- findSub' (('&':pkg) ++ "::" ++ tail name) 
    1078         if isJust subs then return subs else do 
    1079         findWithSuper pkg name 
    1080     findWithSuper :: String -> String -> Eval (Maybe VCode) 
    1081     findWithSuper pkg name = do 
    1082         -- get superclasses 
    1083         attrs <- fmap (fmap (filter (/= pkg) . nub)) $ findAttrs pkg 
    1084         if isNothing attrs || null (fromJust attrs) then findSub' name else do 
    1085         (`fix` (fromJust attrs)) $ \run pkgs -> do 
    1086             if null pkgs then return Nothing else do 
    1087             subs <- findWithPkg (head pkgs) name 
    1088             if isJust subs then return subs else run (tail pkgs) 
    1089     findSub' :: String -> Eval (Maybe VCode) 
    1090     findSub' name = do 
    1091         subSyms     <- findSyms name 
    1092         lens        <- mapM argSlurpLen (unwrap $ maybeToList invs ++ args) 
    1093         doFindSub (sum lens) subSyms 
    1094     argSlurpLen :: Exp -> Eval Int 
    1095     argSlurpLen (Val listMVal) = do 
    1096         listVal  <- fromVal listMVal 
    1097         return $ length (vCast listVal :: [Val]) 
    1098     argSlurpLen (Var name) = do 
    1099         listMVal <- evalVar name 
    1100         listVal  <- fromVal listMVal 
    1101         return $ length (vCast listVal :: [Val]) 
    1102     argSlurpLen (Syn "," list) =  return $ length list 
    1103     argSlurpLen _ = return 1 -- XXX 
    1104     doFindSub :: Int -> [(String, Val)] -> Eval (Maybe VCode) 
    1105     doFindSub slurpLen subSyms = do 
    1106         subs' <- subs slurpLen subSyms 
    1107         -- let foo (x, sub) = show x ++ show (map paramContext $ subParams sub) 
    1108         -- trace (unlines $ map foo $ sort subs') return () 
    1109         return $ case sort subs' of 
    1110             ((_, sub):_)    -> Just sub 
    1111             _               -> Nothing 
    1112     subs :: Int -> [(String, Val)] -> Eval [((Bool, Bool, Int, Int), VCode)] 
    1113     subs slurpLen subSyms = (liftM catMaybes) $ (`mapM` subSyms) $ \(_, val) -> do 
    1114         sub@(MkCode{ subReturns = ret, subParams = prms }) <- fromVal val 
    1115         let rv = return $ arityMatch sub (length (maybeToList invs ++ args)) slurpLen 
    1116         maybeM rv $ \fun -> do 
    1117             -- if deltaFromCxt ret == 0 then return Nothing else do 
    1118             let pairs = map (typeOfCxt . paramContext) prms 
    1119                             `zip` (map unwrap $ maybeToList invs ++ args) 
    1120             deltaCxt    <- deltaFromCxt ret 
    1121             deltaArgs   <- mapM deltaFromPair pairs 
    1122             let bound = either (const False) (const True) $ bindParams sub invs args 
    1123             return ((isMulti sub, bound, sum deltaArgs, deltaCxt), fun) 
    1124     deltaFromCxt :: Type -> Eval Int 
    1125     deltaFromCxt x  = do 
    1126         cls <- asks envClasses 
    1127         cxt <- asks envContext 
    1128         return $ deltaType cls (typeOfCxt cxt) x 
    1129     deltaFromPair (x, y) = do 
    1130         cls <- asks envClasses 
    1131         typ <- evalExpType y 
    1132         return $ deltaType cls x typ 
    1133  
    1134 evalExpType :: Exp -> Eval Type 
    1135 evalExpType (Var var) = do 
    1136     rv  <- findVar var 
    1137     case rv of 
    1138         Nothing  -> return $ typeOfSigil (head var) 
    1139         Just ref -> evalValType (VRef ref) 
    1140 evalExpType (Val val) = evalValType val 
    1141 evalExpType (App (Val val) _ _) = do 
    1142     sub <- fromVal val 
    1143     return $ subReturns sub 
    1144 evalExpType (App (Var "&new") (Just (Var (':':name))) _) = return $ mkType name 
    1145 evalExpType (App (Var name) invs args) = do 
    1146     sub <- findSub name invs args 
    1147     case sub of 
    1148         Just sub    -> return $ subReturns sub 
    1149         Nothing     -> return $ mkType "Any" 
    1150 evalExpType exp@(Syn syn _) | (syn ==) `any` words "{} []" = do 
    1151     val <- evalExp exp 
    1152     evalValType val 
    1153 evalExpType (Cxt cxt _) | typeOfCxt cxt /= (mkType "Any") = return $ typeOfCxt cxt 
    1154 evalExpType (Cxt _ exp) = evalExpType exp 
    1155 evalExpType (Pos _ exp) = evalExpType exp 
    1156 evalExpType (Pad _ _ exp) = evalExpType exp 
    1157 evalExpType (Sym _ _ exp) = evalExpType exp 
    1158 evalExpType (Stmts _ exp) = evalExpType exp 
    1159 evalExpType (Syn "sub" [exp]) = evalExpType exp 
    1160 evalExpType _ = return $ mkType "Any" 
    1161813 
    1162814chainFun :: Params -> Exp -> Params -> Exp -> [Val] -> Eval Val 
     
    1301953        | otherwise                     = False 
    1302954 
    1303 toPackage :: String -> String -> String 
    1304 toPackage pkg name 
    1305     | (sigil, identifier) <- break (\x -> isAlpha x || x == '_') name 
    1306     , last sigil /= '*' 
    1307     = concat [sigil, pkg, "::", identifier] 
    1308     | otherwise = name 
    1309  
    1310 toGlobal :: String -> String 
    1311 toGlobal name 
    1312     | (sigil, identifier) <- break (\x -> isAlpha x || x == '_') name 
    1313     , last sigil /= '*' 
    1314     = sigil ++ ('*':identifier) 
    1315     | otherwise = name 
    1316  
    1317  
    1318 arityMatch :: VCode -> Int -> Int -> Maybe VCode 
    1319 arityMatch sub@MkCode{ subAssoc = assoc, subParams = prms } argLen argSlurpLen 
    1320     | assoc == "list" || assoc == "chain" 
    1321     = Just sub 
    1322     | isNothing $ find (not . isSlurpy) prms -- XXX - what about empty ones? 
    1323     , assoc == "pre" 
    1324     , slurpLen <- length $ filter (\p -> isSlurpy p && head (paramName p) == '$') prms 
    1325     , hasArray <- isJust $ find (\p -> isSlurpy p && head (paramName p) /= '$') prms 
    1326     , if hasArray then slurpLen <= argSlurpLen else slurpLen == argSlurpLen 
    1327     = Just sub 
    1328     | reqLen <- length $ filter (\p -> not (isOptional p || isSlurpy p)) prms 
    1329     , optLen <- length $ filter (\p -> isOptional p) prms 
    1330     , hasArray <- isJust $ find (\p -> isSlurpy p && head (paramName p) /= '$') prms 
    1331     , argLen >= reqLen && (hasArray || argLen <= (reqLen + optLen)) 
    1332     = Just sub 
    1333     | otherwise 
    1334     = Nothing 
    1335  
    1336955doFetch :: (Val -> Eval (IVar VScalar)) 
    1337956        -> (Val -> Eval Val) 
  • src/Pugs/Parser.hs

    r4508 r4544  
    198198        , do (symbol "submethod" <|> symbol "method") 
    199199             return SubMethod 
     200        , do symbol "macro" 
     201             return SubMacro 
    200202        ] 
    201203    name    <- ruleSubName 
     
    12311233            else parseParenParamList <|> do { whiteSpace; parseNoParenParamList } 
    12321234    -- XXX - warn when there's both inv and inv' 
    1233     return $ App (Var name) (inv `mplus` inv') args 
     1235    possiblyApplyMacro $ App (Var name) (inv `mplus` inv') args 
    12341236 
    12351237ruleFoldOp :: RuleParser String 
     
    14521454    name <- choice $ map symbol $ words nullary 
    14531455    notFollowedBy (char '(') 
    1454     return $ App (Var ('&':name)) Nothing [] 
     1456    possiblyApplyMacro $ App (Var ('&':name)) Nothing [] 
    14551457 
    14561458undefLiteral :: RuleParser Exp 
  • src/Pugs/Parser/Unsafe.hs

    r4422 r4544  
    44    unsafeEvalEnv, 
    55    unsafeEvalExp, 
     6    possiblyApplyMacro, 
    67) where 
    78import Pugs.Internals 
     
    910import Pugs.Pretty 
    1011import Pugs.Parser.Types 
     12import Pugs.Eval.Var 
     13import Pugs.Types 
    1114 
    1215unsafeEvalLexDiff :: Exp -> RuleParser Pad 
     
    2932        _  -> error $ pretty val 
    3033 
     34{-# NOINLINE unsafeEvalExp #-} 
    3135unsafeEvalExp :: Exp -> RuleParser Exp 
    3236unsafeEvalExp exp = do 
     
    4044        VError _ _  -> error $ pretty (val :: Val) 
    4145        _           -> return $ Val val 
     46 
     47{-# NOINLINE possiblyApplyMacro #-} 
     48{-| @possiblyApplyMacro@ takes an @Exp@ containg only an @App@. It then checks 
     49    if the code to be executed is a reference to a macro. If it is, the macro 
     50    is executed now, i.e. during compile-time. The return value of the macro is 
     51    then processed accordingly (i.e. a return value of type @Str@ will be 
     52    parsed, and a @Code@ will be executed during runtime). 
     53-} 
     54possiblyApplyMacro :: Exp            -- ^ The @Exp@ containg only an @App@ to 
     55                                     --   check if it calls a macro 
     56                   -> RuleParser Exp -- ^ The result expression (either the 
     57                                     --   original one or the result of 
     58                                     --   applying the macro) 
     59possiblyApplyMacro app@(App (Var name) _ _) = do 
     60    -- First, we've to resolve name to a vcode. 
     61    env <- getRuleEnv 
     62    -- Note that we don't have to clearDynParsers, as we just do a variable 
     63    -- lookup here. 
     64    let subCode = unsafePerformIO $ runEvalIO (env{ envDebug = Nothing }) $ do 
     65        res <- findVar $ (name :: Var) 
     66        if isJust res 
     67            then readRef $ fromJust res 
     68            else return undef 
     69    case subCode of 
     70        -- If we found a Code var, possibly process it further. 
     71        VCode vcode -> possiblyApplyMacro' vcode app 
     72        -- Else, return the original expression. 
     73        _ -> return app 
     74    where 
     75    possiblyApplyMacro' :: VCode -> Exp -> RuleParser Exp 
     76    possiblyApplyMacro' vcode app 
     77        | subType vcode == SubMacro 
     78        = do 
     79            -- The vcode is a macro! Apply it and substitute its return value. 
     80            ret <- unsafeEvalExp app 
     81            substMacroResult ret 
     82        | otherwise 
     83        = return app 
     84    substMacroResult :: Exp -> RuleParser Exp 
     85    -- A Str should be parsed. 
     86    substMacroResult (Val (VStr code)) = do 
     87        -- This is a hack. We should better parse the code now, instead of 
     88        -- using eval() at compile-time. But we can't import 
     89        -- Pugs.Parser.Program... 
     90        evaled <- unsafeEvalExp $ 
     91            App (Var "&eval") Nothing [Val $ VStr $ "({" ++ code ++ "})[0]"] 
     92        return $ App evaled Nothing [] 
     93    -- A Code does not need to be parsed, so simply return the equivalent of 
     94    --  $code(). 
     95    substMacroResult code@(Val (VCode _)) = do 
     96        return $ App code Nothing [] 
     97    substMacroResult _ = fail "Macro did not return a Str or a Code!" 
     98possiblyApplyMacro _ = fail "possiblyApplyMacro can only be passed a (App ...)." 
  • src/Pugs/Prim.hs

    r4484 r4544  
    4444import Pugs.Prim.Eval 
    4545import Pugs.Prim.Code 
     46import Pugs.Prim.Param 
    4647 
    4748-- |Implementation of 0-ary and variadic primitive operators and functions 
     
    10381039op4 other = \_ _ _ _ -> fail ("Unimplemented 4-ary op: " ++ other) 
    10391040 
    1040 op1HyperPrefix :: VCode -> Val -> Eval Val 
    1041 op1HyperPrefix sub (VRef ref) = do 
    1042     x <- readRef ref 
    1043     op1HyperPrefix sub x 
    1044 op1HyperPrefix sub x 
    1045     | VList x' <- x 
    1046     = fmap VList $ hyperList x' 
    1047     | otherwise 
    1048     = fail "Hyper OP only works on lists" 
    1049     where 
    1050     doHyper x 
    1051         | VRef x' <- x 
    1052         = doHyper =<< readRef x' 
    1053         | otherwise 
    1054         = enterEvalContext cxtItemAny $ App (Val $ VCode sub) Nothing [Val x] 
    1055     hyperList []     = return [] 
    1056     hyperList (x:xs) = do 
    1057         val  <- doHyper x 
    1058         rest <- hyperList xs 
    1059         return (val:rest) 
    1060  
    1061 op1HyperPostfix :: VCode -> Val -> Eval Val 
    1062 op1HyperPostfix = op1HyperPrefix 
    1063  
    1064 op2Hyper :: VCode -> Val -> Val -> Eval Val 
    1065 op2Hyper sub (VRef ref) y = do 
    1066     x <- readRef ref 
    1067     op2Hyper sub x y 
    1068 op2Hyper sub x (VRef ref) = do 
    1069     y <- readRef ref 
    1070     op2Hyper sub x y 
    1071 op2Hyper sub x y 
    1072     | VList x' <- x, VList y' <- y 
    1073     = fmap VList $ hyperLists x' y' 
    1074     | VList x' <- x 
    1075     = fmap VList $ mapM ((flip doHyper) y) x' 
    1076     | VList y' <- y 
    1077     = fmap VList $ mapM (doHyper x) y' 
    1078     | otherwise 
    1079     = fail "Hyper OP only works on lists" 
    1080     where 
    1081     doHyper x y = enterEvalContext cxtItemAny $ App (Val $ VCode sub) Nothing [Val x, Val y] 
    1082     hyperLists [] [] = return [] 
    1083     hyperLists xs [] = return xs 
    1084     hyperLists [] ys = return ys 
    1085     hyperLists (x:xs) (y:ys) = do 
    1086         val  <- doHyper x y 
    1087         rest <- hyperLists xs ys 
    1088         return (val:rest) 
    1089  
    10901041op1Range :: Val -> Val 
    10911042op1Range (VStr s)    = VList $ map VStr $ strRangeInf s 
     
    12201171    params = map (\p -> p{ isWritable = isLValue p }) prms'' 
    12211172 
    1222 doFoldParam :: String -> String -> [Param] -> [Param] 
    1223 doFoldParam cxt [] []       = [(buildParam cxt "" "$?1" (Val VUndef)) { isLValue = False }] 
    1224 doFoldParam cxt [] (p:ps)   = ((buildParam cxt "" (strInc $ paramName p) (Val VUndef)) { isLValue = False }:p:ps) 
    1225 doFoldParam cxt (s:name) ps = ((buildParam cxt [s] name (Val VUndef)) { isLValue = False } : ps) 
    1226  
    1227 foldParam :: String -> Params -> Params 
    1228 foldParam "Named" = \ps -> ( 
    1229     (buildParam "Hash" "*" "@?0" (Val VUndef)): 
    1230     (buildParam "Hash" "*" "%?0" (Val VUndef)):ps) 
    1231 foldParam "List"    = doFoldParam "List" "*@?1" 
    1232 foldParam ('r':'w':'!':"List") = \ps -> ((buildParam "List" "" "@?0" (Val VUndef)) { isLValue = True }:ps) 
    1233 foldParam ('r':'w':'!':str) = \ps -> ((buildParam str "" "$?1" (Val VUndef)) { isLValue = True }:ps) 
    1234 foldParam ""        = id 
    1235 foldParam ('?':str) 
    1236     | ('r':'w':'!':typ) <- str 
    1237     = \ps -> ((buildParam typ "?" "$?1" (Val VUndef)) { isLValue = True }:ps) 
    1238     | (('r':'w':'!':typ), "=$_") <- break (== '=') str 
    1239     = \ps -> ((buildParam typ "?" "$?1" (Var "$_")) { isLValue = True }:ps) 
    1240     | (typ, "=$_") <- break (== '=') str 
    1241     = \ps -> ((buildParam typ "?" "$?1" (Var "$_")) { isLValue = False }:ps) 
    1242     | (typ, ('=':def)) <- break (== '=') str 
    1243     = let readVal "Num" = Val . VNum . read 
    1244           readVal "Int" = Val . VInt . read 
    1245           readVal "Str" = Val . VStr . read 
    1246           readVal x     = error $ "Unknown type: " ++ x 
    1247       in \ps -> ((buildParam typ "?" "$?1" (readVal typ def)) { isLValue = False }:ps) 
    1248     | otherwise 
    1249     = \ps -> (buildParam str "?" "$?1" (Val VUndef):ps) 
    1250 foldParam ('~':str) = \ps -> (((buildParam str "" "$?1" (Val VUndef)) { isLValue = False }) { isLazy = True }:ps) 
    1251 foldParam x         = doFoldParam x [] 
    12521173 
    12531174-- op1 "perl" 
  • src/Pugs/Prim/List.hs

    r3906 r4544  
     1{-# OPTIONS_GHC -fglasgow-exts #-} 
     2 
    13module Pugs.Prim.List ( 
    24    op0Zip, op1Pick, op1Sum, 
     
    46    op2FoldL, op2Fold, op2Grep, op2Map, op2Join, 
    57    sortByM, 
     8    op1HyperPrefix, op1HyperPostfix, op2Hyper, 
    69) where 
    710import Pugs.Internals 
    811import Pugs.AST 
    912import Pugs.Types 
     13import Pugs.Monads 
    1014import qualified Data.Set as Set 
    1115 
     
    285289                rest <- doMerge f (x:xs) ys 
    286290                return (y:rest) 
     291 
     292op1HyperPrefix :: VCode -> Val -> Eval Val