| 179 | | inv = fromJust invs |
| 180 | | |
| 181 | | findSuperSub :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) |
| 182 | | => Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| 183 | | findSuperSub pkg var = do |
| 184 | | subs <- findWithSuper pkg var |
| 185 | | subs' <- either (flip findBuiltinSub var) (return . Right) subs |
| 186 | | case subs' of |
| 187 | | -- Recursion prevention -- SUPER::foo should not go back to ThisClas::foo |
| 188 | | Right sub | cast (Str.cons '&' $ subName sub) == var{ v_package = pkg } -> do |
| 189 | | return (Left . NoSuchMethod $ cast pkg) |
| 190 | | _ -> do |
| 191 | | return subs' |
| 192 | | |
| 193 | | findTypedSub :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) |
| 194 | | => Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| 195 | | findTypedSub pkg var = do |
| 196 | | subs <- findWithPkg pkg var |
| 197 | | either (flip findBuiltinSub var) (return . Right) subs |
| 198 | | |
| 199 | | evalInvType :: Exp -> Eval Type |
| 200 | | evalInvType x = inferExpType $ unwrap x |
| 201 | | |
| 202 | | withExternalCall callMeth inv = do |
| 203 | | fmap (err . NoSuchMethod $ valType inv) $ do |
| 204 | | metaSub <- possiblyBuildMetaopVCode ?var |
| 205 | | if isJust metaSub then return metaSub else callMeth |
| 206 | | |
| 207 | | callMethodVV :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) |
| 208 | | => Eval (Maybe VCode) |
| 209 | | callMethodVV = do |
| 210 | | let methName = cast (v_name ?var) |
| 211 | | -- Look up the proto for the method in VV land right here |
| 212 | | -- Whether it matched or not, it's the proto's signature |
| 213 | | -- that's available to the inferencer, not any of its children's |
| 214 | | -- (this is because MMD in newland is performed _after_ everything |
| 215 | | -- has been reduced.) |
| 216 | | return . Just $ mkPrim |
| 217 | | { subName = methName |
| 218 | | , subParams = makeParams ["Object", "List", "Named"] |
| 219 | | , subReturns = mkType "Any" |
| 220 | | , subBody = Prim $ \(inv:named:pos:_) -> do |
| 221 | | invVV <- fromVal inv :: Eval Val.Val |
| 222 | | posVVs <- fromVals pos :: Eval [Val.Val] |
| 223 | | namVVs <- do |
| 224 | | list <- fromVal named |
| 225 | | fmap Map.fromList $ forM list $ \(k, v) -> do |
| 226 | | key <- fromVal k |
| 227 | | val <- fromVal v |
| 228 | | return (key, [val]) :: Eval (ID, [Val.Val]) |
| 229 | | |
| 230 | | -- This is the Capture object we are going to work with |
| 231 | | let capt = CaptMeth invVV [MkFeed posVVs namVVs] |
| 232 | | |
| 233 | | return . castV $ "CCall " ++ show methName ++ " " ++ show capt |
| 234 | | } |
| 235 | | |
| 236 | | callMethodPerl5 :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) |
| 237 | | => Eval (Maybe VCode) |
| 238 | | callMethodPerl5 = do |
| 239 | | let name = cast (v_name ?var) |
| 240 | | return . Just $ mkPrim |
| 241 | | { subName = name |
| 242 | | , subParams = makeParams ["Object", "List", "Named"] |
| 243 | | , subReturns = mkType "Scalar::Perl5" |
| 244 | | , subBody = Prim $ \(inv:named:pos:_) -> do |
| 245 | | sv <- fromVal inv |
| 246 | | posSVs <- fromVals pos |
| 247 | | namSVs <- fmap concat (fromVals named) |
| 248 | | let svs = posSVs ++ namSVs |
| 249 | | found <- liftIO $ canPerl5 sv name |
| 250 | | found' <- liftIO $ if found |
| 251 | | then return found |
| 252 | | else canPerl5 sv (__"AUTOLOAD") |
| 253 | | if not found' |
| 254 | | then do |
| 255 | | -- XXX - when svs is empty, this could call back here infinitely |
| 256 | | -- add an extra '&' to force no-reinterpretation. |
| 257 | | evalExp $ |
| 258 | | App (Var ?var{ v_sigil = SCodeMulti }) Nothing |
| 259 | | (map (Val . PerlSV) (sv:svs)) |
| 260 | | else do |
| 261 | | subSV <- liftIO . bufToSV $ name |
| 262 | | runInvokePerl5 subSV sv svs |
| 263 | | } |
| 264 | | |
| 265 | | findWithPkg :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) |
| 266 | | => Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| 267 | | findWithPkg pkg var = do |
| 268 | | subs <- findSub' var{ v_package = pkg } |
| 269 | | maybe (findWithSuper pkg var) (return . Right) subs |
| 270 | | |
| 271 | | findWithSuper :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) |
| 272 | | => Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| 273 | | findWithSuper pkg var = do |
| 274 | | -- get superclasses |
| 275 | | attrs <- fmap (fmap (filter (/= pkg) . nub)) $ findAttrs pkg |
| 276 | | if isNothing attrs || null (fromJust attrs) then fmap (err NoMatchingMulti) (findSub' var) else do |
| 277 | | (`fix` (fromJust attrs)) $ \run pkgs -> do |
| 278 | | if null pkgs then return (Left $ NoSuchMethod (cast pkg)) else do |
| 279 | | subs <- findWithPkg (head pkgs) var |
| 280 | | either (const $ run (tail pkgs)) (return . Right) subs |
| 281 | | |
| 282 | | findSub' :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) => Var -> Eval (Maybe VCode) |
| 283 | | findSub' var = do |
| 284 | | subSyms <- findSyms var |
| 285 | | lens <- mapM argSlurpLen (unwrap $ maybeToList ?invs ++ ?args) |
| 286 | | doFindSub (sum lens) subSyms |
| 287 | | |
| 288 | | argSlurpLen :: Exp -> Eval Int |
| 289 | | argSlurpLen (Val val) = valSlurpLen val |
| 290 | | argSlurpLen (Var name) = do |
| 291 | | val <- evalExp (Var name) |
| 292 | | valSlurpLen val |
| 293 | | argSlurpLen (Syn "," list) = return $ length list |
| 294 | | argSlurpLen _ = return 1 -- XXX |
| 295 | | |
| 296 | | valSlurpLen :: Val -> Eval Int |
| 297 | | valSlurpLen (VList list) = return $ length list |
| 298 | | valSlurpLen (VRef (MkRef (IArray av))) = array_fetchSize av |
| 299 | | valSlurpLen (VRef (MkRef (IHash hv))) = hash_fetchSize hv |
| 300 | | valSlurpLen _ = return 1 -- XXX |
| 301 | | |
| 302 | | doFindSub :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) |
| 303 | | => Int -> [(Var, Val)] -> Eval (Maybe VCode) |
| 304 | | doFindSub slurpLen subSyms = do |
| 305 | | subs' <- subs slurpLen subSyms |
| 306 | | -- let foo (x, sub) = show x ++ show (map paramContext $ subParams sub) |
| 307 | | -- trace (unlines $ map foo $ sort subs') return () |
| 308 | | return $ case sort subs' of |
| 309 | | ((_, sub):_) -> Just sub |
| 310 | | _ -> Nothing |
| 311 | | |
| 312 | | subs :: (?invs :: Maybe Exp, ?args :: [Exp]) |
| 313 | | => Int -> [(Var, Val)] -> Eval [((Bool, Bool, Int, Int), VCode)] |
| 314 | | subs slurpLen subSyms = fmap catMaybes . forM subSyms $ \(_, val) -> do |
| 315 | | sub@(MkCode{ subReturns = ret, subParams = prms }) <- fromVal val |
| 316 | | let rv = return $ arityMatch sub (length (maybeToList ?invs ++ ?args)) slurpLen |
| 317 | | maybeM rv $ \fun -> do |
| 318 | | -- if deltaFromCxt ret == 0 then return Nothing else do |
| 319 | | let pairs = map (typeOfCxt . paramContext) prms |
| 320 | | `zip` (map unwrap $ maybeToList ?invs ++ ?args) |
| 321 | | deltaCxt <- deltaFromCxt ret |
| 322 | | deltaArgs <- mapM deltaFromPair pairs |
| 323 | | let bound = either (const False) (const True) $ bindParams sub ?invs ?args |
| 324 | | return ((isMulti sub, bound, sum deltaArgs, deltaCxt), fun) |
| 325 | | |
| 326 | | findBuiltinSub :: (?var :: Var, ?invs :: Maybe Exp, ?args :: [Exp]) |
| 327 | | => FindSubFailure -> Var -> Eval (Either FindSubFailure VCode) |
| 328 | | findBuiltinSub failure var = do |
| 329 | | sub <- findSub' var |
| 330 | | maybe (fmap (err failure) $ possiblyBuildMetaopVCode var) (return . Right) sub |
| 331 | | |
| 332 | | firstArg :: (?args :: [Exp]) => [Exp] |
| 333 | | firstArg = [maybe (Val undef) id (listToMaybe ?args)] |
| 334 | | |
| 335 | | buildPrefixHyper name var = do |
| 336 | | let rv = fmap (either (const Nothing) Just) $ |
| 337 | | findSub var Nothing firstArg |
| 338 | | maybeM rv $ \code -> return $ mkPrim |
| 339 | | { subName = name |
| 340 | | , subType = SubPrim |
| 341 | | , subAssoc = subAssoc code |
| 342 | | , subParams = subParams code |
| 343 | | , subReturns = mkType "List" |
| 344 | | , subBody = Prim |
| 345 | | (\x -> op1HyperPrefix code (listArg x)) |
| 346 | | } |
| 347 | | |
| 348 | | buildPostfixHyper name var = do |
| 349 | | let rv = fmap (either (const Nothing) Just) $ |
| 350 | | findSub var Nothing firstArg |
| 351 | | maybeM rv $ \code -> return $ mkPrim |
| 352 | | { subName = name |
| 353 | | , subType = SubPrim |
| 354 | | , subAssoc = subAssoc code |
| 355 | | , subParams = subParams code |
| 356 | | , subReturns = mkType "List" |
| 357 | | , subBody = Prim |
| 358 | | (\x -> op1HyperPostfix code (listArg x)) |
| 359 | | } |
| 360 | | |
| 361 | | buildInfixHyper name var = do |
| 362 | | let rv = fmap (either (const Nothing) Just) $ |
| 363 | | findSub var Nothing (take 2 (?args ++ [Val undef, Val undef])) |
| 364 | | maybeM rv $ \code -> return $ mkPrim |
| 365 | | { subName = name |
| 366 | | , subType = SubPrim |
| 367 | | , subAssoc = subAssoc code |
| 368 | | , subParams = makeParams ["Any", "Any"] |
| 369 | | , subReturns = mkType "List" |
| 370 | | , subBody = Prim (\[x, y] -> op2Hyper code x y) |
| 371 | | } |
| 372 | | |
| 373 | | possiblyBuildMetaopVCode :: (?args :: [Exp]) => Var -> Eval (Maybe VCode) |
| 374 | | possiblyBuildMetaopVCode var@MkVar{ v_categ = cat, v_name = name } |
| 375 | | | C_prefix <- cat, '\171' <- Str.last buf = do |
| 376 | | buildPrefixHyper buf var{ v_name = cast $ Str.init buf } |
| 377 | | | C_prefix <- cat, __"<<" `Str.isSuffixOf` buf = do |
| 378 | | buildPrefixHyper buf var{ v_name = cast $ dropEnd 2 buf } |
| 379 | | | C_postfix <- cat, '\187' <- Str.head buf = do |
| 380 | | buildPostfixHyper buf var{ v_name = cast $ Str.tail buf } |
| 381 | | | C_postfix <- cat, __">>" `Str.isPrefixOf` buf = do |
| 382 | | buildPostfixHyper buf var{ v_name = cast $ Str.drop 2 buf } |
| 383 | | | C_infix <- cat, '\187' <- Str.head buf, '\171' <- Str.last buf = do |
| 384 | | buildInfixHyper buf var{ v_name = cast $ Str.init (Str.tail buf) } |
| 385 | | | C_infix <- cat, __">>" `Str.isPrefixOf` buf, __"<<" `Str.isSuffixOf` buf = do |
| 386 | | buildInfixHyper buf var{ v_name = cast $ Str.take 2 (dropEnd 2 buf) } |
| 387 | | | C_prefix <- cat, '[' <- Str.head buf, ']' <- Str.last buf = do |
| 388 | | -- Strip the trailing "]" from op |
| 389 | | let (op, keep) |
| 390 | | | Str.index buf 1 == '\\' = (Str.drop 2 (Str.init buf), True) |
| 391 | | | otherwise = (Str.tail (Str.init buf), False) |
| 392 | | |
| 393 | | -- We try to find the userdefined sub. |
| 394 | | -- We use the first two elements of invs as invocants, as these are the |
| 395 | | -- types of the op. |
| 396 | | rv = fmap (either (const Nothing) Just) $ |
| 397 | | findSub (var{ v_categ = C_infix, v_name = cast op }) Nothing |
| 398 | | (take 2 $ ?args ++ [Val undef, Val undef]) |
| | 175 | _inv = fromJust _invs |
| | 176 | |
| | 177 | -- findSuperSub :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) |
| | 178 | -- => Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| | 179 | findSuperSub pkg var = do |
| | 180 | subs <- findWithSuper pkg var |
| | 181 | subs' <- either (flip findBuiltinSub var) (return . Right) subs |
| | 182 | case subs' of |
| | 183 | -- Recursion prevention -- SUPER::foo should not go back to ThisClas::foo |
| | 184 | Right sub | cast (Str.cons '&' $ subName sub) == var{ v_package = pkg } -> do |
| | 185 | return (Left . NoSuchMethod $ cast pkg) |
| | 186 | _ -> do |
| | 187 | return subs' |
| | 188 | |
| | 189 | -- findTypedSub :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) |
| | 190 | -- => Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| | 191 | findTypedSub pkg var = do |
| | 192 | subs <- findWithPkg pkg var |
| | 193 | either (flip findBuiltinSub var) (return . Right) subs |
| | 194 | |
| | 195 | evalInvType :: Exp -> Eval Type |
| | 196 | evalInvType x = inferExpType $ unwrap x |
| | 197 | |
| | 198 | withExternalCall callMeth inv = do |
| | 199 | fmap (err . NoSuchMethod $ valType inv) $ do |
| | 200 | metaSub <- possiblyBuildMetaopVCode _var |
| | 201 | if isJust metaSub then return metaSub else callMeth |
| | 202 | |
| | 203 | -- callMethodVV :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) |
| | 204 | -- => Eval (Maybe VCode) |
| | 205 | callMethodVV = do |
| | 206 | let methName = cast (v_name _var) |
| | 207 | -- Look up the proto for the method in VV land right here |
| | 208 | -- Whether it matched or not, it's the proto's signature |
| | 209 | -- that's available to the inferencer, not any of its children's |
| | 210 | -- (this is because MMD in newland is performed _after_ everything |
| | 211 | -- has been reduced.) |
| | 212 | return . Just $ mkPrim |
| | 213 | { subName = methName |
| | 214 | , subParams = makeParams ["Object", "List", "Named"] |
| | 215 | , subReturns = mkType "Any" |
| | 216 | , subBody = Prim $ \(inv:named:pos:_) -> do |
| | 217 | invVV <- fromVal inv :: Eval Val.Val |
| | 218 | posVVs <- fromVals pos :: Eval [Val.Val] |
| | 219 | namVVs <- do |
| | 220 | list <- fromVal named |
| | 221 | fmap Map.fromList $ forM list $ \(k, v) -> do |
| | 222 | key <- fromVal k |
| | 223 | val <- fromVal v |
| | 224 | return (key, [val]) :: Eval (ID, [Val.Val]) |
| | 225 | |
| | 226 | -- This is the Capture object we are going to work with |
| | 227 | let capt = CaptMeth invVV [MkFeed posVVs namVVs] |
| | 228 | |
| | 229 | return . castV $ "CCall " ++ show methName ++ " " ++ show capt |
| | 230 | } |
| | 231 | |
| | 232 | -- callMethodPerl5 :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) |
| | 233 | -- => Eval (Maybe VCode) |
| | 234 | callMethodPerl5 = do |
| | 235 | let name = cast (v_name _var) |
| | 236 | return . Just $ mkPrim |
| | 237 | { subName = name |
| | 238 | , subParams = makeParams ["Object", "List", "Named"] |
| | 239 | , subReturns = mkType "Scalar::Perl5" |
| | 240 | , subBody = Prim $ \(inv:named:pos:_) -> do |
| | 241 | sv <- fromVal inv |
| | 242 | posSVs <- fromVals pos |
| | 243 | namSVs <- fmap concat (fromVals named) |
| | 244 | let svs = posSVs ++ namSVs |
| | 245 | found <- liftIO $ canPerl5 sv name |
| | 246 | found' <- liftIO $ if found |
| | 247 | then return found |
| | 248 | else canPerl5 sv (__"AUTOLOAD") |
| | 249 | if not found' |
| | 250 | then do |
| | 251 | -- XXX - when svs is empty, this could call back here infinitely |
| | 252 | -- add an extra '&' to force no-reinterpretation. |
| | 253 | evalExp $ |
| | 254 | App (Var _var{ v_sigil = SCodeMulti }) Nothing |
| | 255 | (map (Val . PerlSV) (sv:svs)) |
| | 256 | else do |
| | 257 | subSV <- liftIO . bufToSV $ name |
| | 258 | runInvokePerl5 subSV sv svs |
| | 259 | } |
| | 260 | |
| | 261 | -- findWithPkg :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) |
| | 262 | -- => Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| | 263 | findWithPkg pkg var = do |
| | 264 | subs <- findSub' var{ v_package = pkg } |
| | 265 | maybe (findWithSuper pkg var) (return . Right) subs |
| | 266 | |
| | 267 | -- findWithSuper :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) |
| | 268 | -- => Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| | 269 | findWithSuper pkg var = do |
| | 270 | -- get superclasses |
| | 271 | attrs <- fmap (fmap (filter (/= pkg) . nub)) $ findAttrs pkg |
| | 272 | if isNothing attrs || null (fromJust attrs) then fmap (err NoMatchingMulti) (findSub' var) else do |
| | 273 | (`fix` (fromJust attrs)) $ \run pkgs -> do |
| | 274 | if null pkgs then return (Left $ NoSuchMethod (cast pkg)) else do |
| | 275 | subs <- findWithPkg (head pkgs) var |
| | 276 | either (const $ run (tail pkgs)) (return . Right) subs |
| | 277 | |
| | 278 | -- findSub' :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) => Var -> Eval (Maybe VCode) |
| | 279 | findSub' var = do |
| | 280 | subSyms <- findSyms var |
| | 281 | lens <- mapM argSlurpLen (unwrap $ maybeToList _invs ++ _args) |
| | 282 | doFindSub (sum lens) subSyms |
| | 283 | |
| | 284 | argSlurpLen :: Exp -> Eval Int |
| | 285 | argSlurpLen (Val val) = valSlurpLen val |
| | 286 | argSlurpLen (Var name) = do |
| | 287 | val <- evalExp (Var name) |
| | 288 | valSlurpLen val |
| | 289 | argSlurpLen (Syn "," list) = return $ length list |
| | 290 | argSlurpLen _ = return 1 -- XXX |
| | 291 | |
| | 292 | valSlurpLen :: Val -> Eval Int |
| | 293 | valSlurpLen (VList list) = return $ length list |
| | 294 | valSlurpLen (VRef (MkRef (IArray av))) = array_fetchSize av |
| | 295 | valSlurpLen (VRef (MkRef (IHash hv))) = hash_fetchSize hv |
| | 296 | valSlurpLen _ = return 1 -- XXX |
| | 297 | |
| | 298 | -- doFindSub :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) |
| | 299 | -- => Int -> [(Var, Val)] -> Eval (Maybe VCode) |
| | 300 | doFindSub slurpLen subSyms = do |
| | 301 | subs' <- subs slurpLen subSyms |
| | 302 | -- let foo (x, sub) = show x ++ show (map paramContext $ subParams sub) |
| | 303 | -- trace (unlines $ map foo $ sort subs') return () |
| | 304 | return $ case sort subs' of |
| | 305 | ((_, sub):_) -> Just sub |
| | 306 | _ -> Nothing |
| | 307 | |
| | 308 | -- subs :: (_invs :: Maybe Exp, _args :: [Exp]) |
| | 309 | -- => Int -> [(Var, Val)] -> Eval [((Bool, Bool, Int, Int), VCode)] |
| | 310 | subs slurpLen subSyms = fmap catMaybes . forM subSyms $ \(_, val) -> do |
| | 311 | sub@(MkCode{ subReturns = ret, subParams = prms }) <- fromVal val |
| | 312 | let rv = return $ arityMatch sub (length (maybeToList _invs ++ _args)) slurpLen |
| | 313 | maybeM rv $ \fun -> do |
| | 314 | -- if deltaFromCxt ret == 0 then return Nothing else do |
| | 315 | let pairs = map (typeOfCxt . paramContext) prms |
| | 316 | `zip` (map unwrap $ maybeToList _invs ++ _args) |
| | 317 | deltaCxt <- deltaFromCxt ret |
| | 318 | deltaArgs <- mapM deltaFromPair pairs |
| | 319 | let bound = either (const False) (const True) $ bindParams sub _invs _args |
| | 320 | return ((isMulti sub, bound, sum deltaArgs, deltaCxt), fun) |
| | 321 | |
| | 322 | -- findBuiltinSub :: (_var :: Var, _invs :: Maybe Exp, _args :: [Exp]) |
| | 323 | -- => FindSubFailure -> Var -> Eval (Either FindSubFailure VCode) |
| | 324 | findBuiltinSub failure var = do |
| | 325 | sub <- findSub' var |
| | 326 | maybe (fmap (err failure) $ possiblyBuildMetaopVCode var) (return . Right) sub |
| | 327 | |
| | 328 | -- firstArg :: (_args :: [Exp]) => [Exp] |
| | 329 | firstArg = [maybe (Val undef) id (listToMaybe _args)] |
| | 330 | |
| | 331 | buildPrefixHyper name var = do |
| | 332 | let rv = fmap (either (const Nothing) Just) $ |
| | 333 | findSub var Nothing firstArg |