| 36 | | findVarRef name |
| 37 | | | Just (package, name') <- breakOnGlue "::" name |
| 38 | | = case () of |
| 39 | | _ | Just (sig, "") <- breakOnGlue "CALLER" package -> do |
| 40 | | maybeCaller <- asks envCaller |
| 41 | | case maybeCaller of |
| 42 | | Just env -> local (const env) $ do |
| 43 | | rv <- findVarRef (sig ++ name') |
| 44 | | return rv |
| 45 | | Nothing -> retError "cannot access CALLER:: in top level" name |
| 46 | | _ | Just (sig, "") <- breakOnGlue "ENV" package -> fix $ \upLevel -> do |
| 47 | | maybeCaller <- asks envCaller |
| 48 | | case maybeCaller of |
| 49 | | Just env -> local (const env) $ do |
| 50 | | rv <- findVarRef (sig ++ name') |
| 51 | | if isJust rv then return rv else upLevel |
| 52 | | Nothing -> do |
| 53 | | -- final callback: try an "environment" lookup |
| 54 | | -- XXX: how does "@+PATH" differ from "$+PATH"? |
| 55 | | -- XXX: how to tell empty env from nonexistent env? |
| 56 | | -- should we allow writes? |
| 57 | | exists <- evalExp $ App (Var "&exists") (Just (Var "%*ENV")) [Val (VStr name')] |
| 58 | | case exists of |
| 59 | | VBool False -> do |
| 60 | | retError "no such ENV:: variable" name' |
| 61 | | _ -> do |
| 62 | | rv <- enterLValue (evalExp $ Syn "{}" [Var "%*ENV", Val (VStr name')]) |
| 63 | | tvar <- liftSTM . newTVar =<< fromVal rv |
| 64 | | return (Just tvar) |
| 65 | | _ | Just (sig, "") <- breakOnGlue "OUTER" package -> do |
| 66 | | maybeOuter <- asks envOuter |
| 67 | | case maybeOuter of |
| 68 | | Just env -> local (const env) $ do |
| 69 | | findVarRef (sig ++ name') |
| 70 | | Nothing -> retError "cannot access OUTER:: in top level" name |
| 71 | | _ -> doFindVarRef name |
| 72 | | | (sig:'+':name') <- name = findVarRef (sig:("ENV::"++name')) |
| 73 | | | (_:'?':_) <- name = do |
| 74 | | rv <- getMagical name |
| | 51 | findVarRef var@MkVar{ v_sigil = sig, v_twigil = twi, v_name = name, v_package = pkg } |
| | 52 | | Just var' <- dropVarPkg (__"CALLER") var = do |
| | 53 | maybeCaller <- asks envCaller |
| | 54 | case maybeCaller of |
| | 55 | Just env -> local (const env) $ findVarRef var' |
| | 56 | Nothing -> retError "cannot access CALLER:: in top level" var |
| | 57 | |
| | 58 | | Just var' <- dropVarPkg (__"ENV") var = fix $ \upLevel -> do |
| | 59 | maybeCaller <- asks envCaller |
| | 60 | case maybeCaller of |
| | 61 | Just env -> local (const env) $ do |
| | 62 | rv <- findVarRef var' |
| | 63 | if isJust rv then return rv else upLevel |
| | 64 | -- final callback: try an "environment" lookup |
| | 65 | -- XXX: how does "@+PATH" differ from "$+PATH"? |
| | 66 | -- XXX: how to tell empty env from nonexistent env? |
| | 67 | -- should we allow writes? |
| | 68 | Nothing -> lookupShellEnvironment (cast name) |
| | 69 | |
| | 70 | | Just var' <- dropVarPkg (__"OUTER") var = do |
| | 71 | maybeOuter <- asks envOuter |
| | 72 | case maybeOuter of |
| | 73 | Just env -> local (const env) $ findVarRef var' |
| | 74 | Nothing -> retError "cannot access OUTER:: in top level" name |
| | 75 | |
| | 76 | | pkg /= emptyPkg = doFindVarRef var |
| | 77 | |
| | 78 | | TMagical <- twi = do |
| | 79 | rv <- getMagical var |
| 95 | | return (key, val) |
| 96 | | padEntryToHashEntry (_, []) = do fail "Nonexistant var in pad?" |
| 97 | | doFindVarRef :: Var -> Eval (Maybe (TVar VRef)) |
| 98 | | doFindVarRef name = do |
| 99 | | callCC $ \foundIt -> do |
| 100 | | lexSym <- fmap (findSym name . envLexical) ask |
| 101 | | when (isJust lexSym) $ foundIt lexSym |
| 102 | | glob <- liftSTM . readTVar . envGlobal =<< ask |
| 103 | | name' <- toQualified name |
| 104 | | -- XXX - find qualified name here |
| 105 | | let globSym = findSym name' glob |
| 106 | | when (isJust globSym) $ foundIt globSym |
| 107 | | let globSym = findSym (toGlobal name) glob |
| 108 | | when (isJust globSym) $ foundIt globSym |
| 109 | | return Nothing |
| | 101 | return (cast key, val) |
| | 102 | padEntryToHashEntry (_, []) = fail "Nonexistant var in pad?" |
| | 103 | |
| | 104 | doFindVarRef :: Var -> Eval (Maybe (TVar VRef)) |
| | 105 | doFindVarRef var = do |
| | 106 | callCC $ \foundIt -> do |
| | 107 | lexSym <- fmap (findSym var . envLexical) ask |
| | 108 | when (isJust lexSym) $ foundIt lexSym |
| | 109 | -- XXX - this is bogus; we should not fallback if it's not in lex csope. |
| | 110 | glob <- liftSTM . readTVar . envGlobal =<< ask |
| | 111 | var' <- toQualified var |
| | 112 | let globSym = findSym var' glob |
| | 113 | when (isJust globSym) $ foundIt globSym |
| | 114 | -- XXX - ditto for globals |
| | 115 | let globSym = findSym (toGlobalVar var) glob |
| | 116 | when (isJust globSym) $ foundIt globSym |
| | 117 | return Nothing |
| 247 | | possiblyBuildMetaopVCode :: String -> Eval (Maybe VCode) |
| 248 | | possiblyBuildMetaopVCode op'' | "&prefix:[" `isPrefixOf` op'', "]" `isSuffixOf` op'' = do |
| 249 | | -- Strip the trailing "]" from op |
| 250 | | let op' = drop 9 (init op'') |
| 251 | | let (op, keep) | '\\':real <- op' = (real, True) |
| 252 | | | otherwise = (op', False) |
| 253 | | -- We try to find the userdefined sub. |
| 254 | | -- We use the first two elements of invs as invocants, as these are the |
| 255 | | -- types of the op. |
| 256 | | rv = fmap (either (const Nothing) Just) $ findSub ("&infix:" ++ op) Nothing (take 2 $ args ++ [Val undef, Val undef]) |
| 257 | | maybeM rv $ \code -> return $ mkPrim |
| 258 | | { subName = "&prefix:[" ++ (if keep then "\\" else "") ++ op ++ "]" |
| 259 | | , subType = SubPrim |
| 260 | | , subAssoc = "spre" |
| 261 | | , subParams = makeParams $ |
| 262 | | if any isLValue (subParams code) |
| 263 | | then ["rw!List"] -- XXX - does not yet work for the [=] case |
| 264 | | else ["List"] |
| 265 | | , subReturns = anyType |
| 266 | | , subBody = Prim $ \[vs] -> do |
| 267 | | list_of_args <- fromVal vs |
| 268 | | op2Reduce keep list_of_args (VCode code) |
| 269 | | } |
| 270 | | -- Now we construct the sub. Is there a more simple way to do it? |
| 271 | | possiblyBuildMetaopVCode op' | "&prefix:" `isPrefixOf` op', "\171" `isSuffixOf` op' = do |
| 272 | | let op = drop 8 (init op') |
| 273 | | possiblyBuildMetaopVCode ("&prefix:" ++ op ++ "<<") |
| 274 | | possiblyBuildMetaopVCode op' | "&prefix:" `isPrefixOf` op', "<<" `isSuffixOf` op' = do |
| 275 | | let op = drop 8 (init (init op')) |
| 276 | | rv = fmap (either (const Nothing) Just) $ findSub ("&prefix:" ++ op) Nothing [head $ args ++ [Val undef]] |
| 277 | | maybeM rv $ \code -> return $ mkPrim |
| 278 | | { subName = "&prefix:" ++ op ++ "<<" |
| 279 | | , subType = SubPrim |
| 280 | | , subAssoc = subAssoc code |
| 281 | | , subParams = subParams code |
| 282 | | , subReturns = mkType "List" |
| 283 | | , subBody = Prim |
| 284 | | (\x -> op1HyperPrefix code (listArg x)) |
| 285 | | } |
| 286 | | possiblyBuildMetaopVCode op' | "&postfix:\187" `isPrefixOf` op' = do |
| 287 | | let op = drop 10 op' |
| 288 | | possiblyBuildMetaopVCode ("&postfix:>>" ++ op) |
| 289 | | possiblyBuildMetaopVCode op' | "&postfix:>>" `isPrefixOf` op' = do |
| 290 | | let op = drop 11 op' |
| 291 | | rv = fmap (either (const Nothing) Just) $ findSub ("&postfix:" ++ op) Nothing [head $ args ++ [Val undef]] |
| 292 | | maybeM rv $ \code -> return $ mkPrim |
| 293 | | { subName = "&postfix:>>" ++ op |
| 294 | | , subType = SubPrim |
| 295 | | , subAssoc = subAssoc code |
| 296 | | , subParams = subParams code |
| 297 | | , subReturns = mkType "List" |
| 298 | | , subBody = Prim |
| 299 | | (\x -> op1HyperPostfix code (listArg x)) |
| 300 | | } |
| 301 | | possiblyBuildMetaopVCode op' | "&infix:\187" `isPrefixOf` op', "\171" `isSuffixOf` op' = do |
| 302 | | let op = drop 8 (init op') |
| 303 | | possiblyBuildMetaopVCode ("&infix:>>" ++ op ++ "<<") |
| 304 | | possiblyBuildMetaopVCode op' | "&infix:>>" `isPrefixOf` op', "<<" `isSuffixOf` op' = do |
| 305 | | let op = drop 9 (init (init op')) |
| 306 | | rv = fmap (either (const Nothing) Just) $ findSub ("&infix:" ++ op) Nothing (take 2 (args ++ [Val undef, Val undef])) |
| 307 | | maybeM rv $ \code -> return $ mkPrim |
| 308 | | { subName = "&infix:>>" ++ op ++ "<<" |
| 309 | | , subType = SubPrim |
| 310 | | , subAssoc = subAssoc code |
| 311 | | , subParams = makeParams ["Any", "Any"] |
| 312 | | , subReturns = mkType "List" |
| 313 | | , subBody = Prim (\[x, y] -> op2Hyper code x y) |
| 314 | | } |
| 315 | | -- Taken from Pugs.Prim. Probably this should be refactored. (?) |
| 316 | | possiblyBuildMetaopVCode _ = return Nothing |
| 317 | | listArg [x] = x |
| 318 | | listArg xs = VList xs |
| 319 | | makeParams = map (\p -> p{ isWritable = isLValue p }) . foldr foldParam [] . map takeWord |
| 320 | | takeWord = takeWhile isWord . dropWhile (not . isWord) |
| 321 | | isWord = not . (`elem` "(),:") |
| 322 | | findAttrs pkg = do |
| 323 | | maybeM (findVar (':':'*':pkg)) $ \ref -> do |
| 324 | | meta <- readRef ref |
| 325 | | fetch <- doHash meta hash_fetchVal |
| 326 | | fromVal =<< fetch "is" |
| 327 | | findWithPkg :: String -> String -> Eval (Either FindSubFailure VCode) |
| 328 | | findWithPkg pkg name = do |
| 329 | | subs <- findSub' (('&':pkg) ++ "::" ++ tail name) |
| 330 | | maybe (findWithSuper pkg name) (return . Right) subs |
| 331 | | findWithSuper :: String -> String -> Eval (Either FindSubFailure VCode) |
| 332 | | findWithSuper pkg name = do |
| | 254 | |
| | 255 | findWithPkg :: Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| | 256 | findWithPkg pkg var = do |
| | 257 | subs <- findSub' var{ v_package = pkg } |
| | 258 | maybe (findWithSuper pkg var) (return . Right) subs |
| | 259 | |
| | 260 | findWithSuper :: Pkg -> Var -> Eval (Either FindSubFailure VCode) |
| | 261 | findWithSuper pkg var = do |
| 379 | | deltaFromCxt :: Type -> Eval Int |
| 380 | | deltaFromCxt x = do |
| 381 | | cls <- asks envClasses |
| 382 | | cxt <- asks envContext |
| 383 | | return $ deltaType cls (typeOfCxt cxt) x |
| 384 | | deltaFromPair (x, y) = do |
| 385 | | cls <- asks envClasses |
| 386 | | typ <- inferExpType y |
| 387 | | return $ deltaType cls x typ |
| | 308 | |
| | 309 | firstArg = [maybe (Val undef) id (listToMaybe args)] |
| | 310 | |
| | 311 | buildPrefixHyper name var = do |
| | 312 | let rv = fmap (either (const Nothing) Just) $ |
| | 313 | findSub var Nothing firstArg |
| | 314 | maybeM rv $ \code -> return $ mkPrim |
| | 315 | { subName = name |
| | 316 | , subType = SubPrim |
| | 317 | , subAssoc = subAssoc code |
| | 318 | , subParams = subParams code |
| | 319 | , subReturns = mkType "List" |
| | 320 | , subBody = Prim |
| | 321 | (\x -> op1HyperPrefix code (listArg x)) |
| | 322 | } |
| | 323 | |
| | 324 | buildPostfixHyper name var = do |
| | 325 | let rv = fmap (either (const Nothing) Just) $ |
| | 326 | findSub var Nothing firstArg |
| | 327 | maybeM rv $ \code -> return $ mkPrim |
| | 328 | { subName = name |
| | 329 | , subType = SubPrim |
| | 330 | , subAssoc = subAssoc code |
| | 331 | , subParams = subParams code |
| | 332 | , subReturns = mkType "List" |
| | 333 | , subBody = Prim |
| | 334 | (\x -> op1HyperPostfix code (listArg x)) |
| | 335 | } |
| | 336 | |
| | 337 | buildInfixHyper name var = do |
| | 338 | let rv = fmap (either (const Nothing) Just) $ |
| | 339 | findSub var Nothing (take 2 (args ++ [Val undef, Val undef])) |
| | 340 | maybeM rv $ \code -> return $ mkPrim |
| | 341 | { subName = name |
| | 342 | , subType = SubPrim |
| | 343 | , subAssoc = subAssoc code |
| | 344 | , subParams = makeParams ["Any", "Any"] |
| | 345 | , subReturns = mkType "List" |
| | 346 | , subBody = Prim (\[x, y] -> op2Hyper code x y) |
| | 347 | } |
| | 348 | |
| | 349 | possiblyBuildMetaopVCode :: Var -> Eval (Maybe VCode) |
| | 350 | possiblyBuildMetaopVCode var@MkVar{ v_categ = cat, v_name = name } |
| | 351 | | C_prefix <- cat, '\171' <- Str.last buf = do |
| | 352 | buildPrefixHyper buf var{ v_name = cast $ Str.init buf } |
| | 353 | | C_prefix <- cat, __"<<" `Str.isSuffixOf` buf = do |
| | 354 | buildPrefixHyper buf var{ v_name = cast $ dropEnd 2 buf } |
| | 355 | | C_postfix <- cat, '\187' <- Str.head buf = do |
| | 356 | buildPostfixHyper buf var{ v_name = cast $ Str.tail buf } |
| | 357 | | C_postfix <- cat, __">>" `Str.isPrefixOf` buf = do |
| | 358 | buildPostfixHyper buf var{ v_name = cast $ Str.drop 2 buf } |
| | 359 | | C_infix <- cat, '\187' <- Str.head buf, '\171' <- Str.last buf = do |
| | 360 | buildInfixHyper buf var{ v_name = cast $ Str.init (Str.tail buf) } |
| | 361 | | C_infix <- cat, __">>" `Str.isPrefixOf` buf, __"<<" `Str.isSuffixOf` buf = do |
| | 362 | buildInfixHyper buf var{ v_name = cast $ Str.take 2 (dropEnd 2 buf) } |
| | 363 | | C_prefix <- cat, '[' <- Str.head buf, ']' <- Str.last buf = do |
| | 364 | -- Strip the trailing "]" from op |
| | 365 | let (op, keep) |
| | 366 | | Str.index buf 1 == '\\' = (Str.drop 2 (Str.init buf), True) |
| | 367 | | otherwise = (Str.tail (Str.init buf), False) |
| | 368 | |
| | 369 | -- We try to find the userdefined sub. |
| | 370 | -- We use the first two elements of invs as invocants, as these are the |
| | 371 | -- types of the op. |
| | 372 | rv = fmap (either (const Nothing) Just) $ |
| | 373 | findSub (var{ v_categ = C_infix, v_name = cast op }) Nothing |
| | 374 | (take 2 $ args ++ [Val undef, Val undef]) |
| | 375 | maybeM rv $ \code -> return $ mkPrim |
| | 376 | { subName = buf |
| | 377 | , subType = SubPrim |
| | 378 | , subAssoc = "spre" |
| | 379 | , subParams = makeParams $ |
| | 380 | if any isLValue (subParams code) |
| | 381 | then ["rw!List"] -- XXX - does not yet work for the [=] case |
| | 382 | else ["List"] |
| | 383 | , subReturns = anyType |
| | 384 | , subBody = Prim $ \[vs] -> do |
| | 385 | list_of_args <- fromVal vs |
| | 386 | op2Reduce keep list_of_args (VCode code) |
| | 387 | } |
| | 388 | -- Now we construct the sub. Is there a more simple way to do it? |
| | 389 | | otherwise = return Nothing |
| | 390 | where |
| | 391 | buf = cast name |
| | 392 | |
| | 393 | metaVar :: Pkg -> Var |
| | 394 | -- metaVar = MkVar SType TNone globalPkg CNone . cast |
| | 395 | metaVar pkg = MkVar |
| | 396 | { v_sigil = SType |
| | 397 | , v_twigil = TGlobal |
| | 398 | , v_package = emptyPkg |
| | 399 | , v_categ = CNone |
| | 400 | , v_name = cast pkg |
| | 401 | } |
| | 402 | |
| | 403 | err :: b -> Maybe a -> Either b a |
| | 404 | err _ (Just j) = Right j |
| | 405 | err x Nothing = Left x |
| | 406 | |
| | 407 | listArg :: [Val] -> Val |
| | 408 | listArg [x] = x |
| | 409 | listArg xs = VList xs |
| | 410 | |
| | 411 | makeParams :: [String] -> [Param] |
| | 412 | makeParams = map (\p -> p{ isWritable = isLValue p }) . foldr foldParam [] . map takeWord |
| | 413 | where |
| | 414 | takeWord = takeWhile isWord . dropWhile (not . isWord) |
| | 415 | isWord = not . (`elem` "(),:") |
| | 416 | |
| | 417 | deltaFromCxt :: Type -> Eval Int |
| | 418 | deltaFromCxt x = do |
| | 419 | cls <- asks envClasses |
| | 420 | cxt <- asks envContext |
| | 421 | return $ deltaType cls (typeOfCxt cxt) x |
| | 422 | |
| | 423 | deltaFromPair :: (Type, Exp) -> Eval Int |
| | 424 | deltaFromPair (x, y) = do |
| | 425 | cls <- asks envClasses |
| | 426 | typ <- inferExpType y |
| | 427 | return $ deltaType cls x typ |
| | 428 | |
| | 429 | findAttrs pkg = do |
| | 430 | maybeM (findVar $ metaVar pkg) $ \ref -> do |
| | 431 | meta <- readRef ref |
| | 432 | fetch <- doHash meta hash_fetchVal |
| | 433 | fmap (map (cast :: String -> Pkg)) (fromVal =<< fetch "is") |
| 492 | | getMagical "$?FILE" = posSym posName |
| 493 | | getMagical "$?LINE" = posSym posBeginLine |
| 494 | | getMagical "$?COLUMN" = posSym posBeginColumn |
| 495 | | getMagical "$?POSITION" = posSym pretty |
| 496 | | getMagical "$?MODULE" = constSym "main" |
| 497 | | getMagical "$?OS" = constSym $ getConfig "osname" |
| 498 | | getMagical "$?CLASS" = fmap (Just . VType . mkType) (asks envPackage) |
| 499 | | getMagical ":?CLASS" = fmap (Just . VType . mkType) (asks envPackage) |
| 500 | | getMagical "$?PACKAGE" = fmap (Just . VType . mkType) (asks envPackage) |
| 501 | | getMagical ":?PACKAGE" = fmap (Just . VType . mkType) (asks envPackage) |
| 502 | | getMagical "$?ROLE" = fmap (Just . VType . mkType) (asks envPackage) |
| 503 | | getMagical ":?ROLE" = fmap (Just . VType . mkType) (asks envPackage) |
| 504 | | getMagical _ = return Nothing |
| | 541 | getMagical var = Map.findWithDefault (return Nothing) var magicalMap |
| | 542 | |
| | 543 | magicalMap :: Map Var (Eval (Maybe Val)) |
| | 544 | magicalMap = Map.fromList |
| | 545 | [ (cast "$?FILE" , posSym posName) |
| | 546 | , (cast "$?LINE" , posSym posBeginLine) |
| | 547 | , (cast "$?COLUMN" , posSym posBeginColumn) |
| | 548 | , (cast "$?POSITION" , posSym pretty) |
| | 549 |   |