vإ      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ None 9<path to *build* dir, used by eval() for testing the exampleswhat is ghc called?path to standard ghc libraries$name of the system package.conf fileJThis code is from runtime_loader: The extension used by system modules. @The prefix used by system modules. This, in conjunction with systemModuleExtensionD, will result in a module filename that looks like "HSconcurrent.o" '_' on a.out, and Darwin CDefine tmpDir to where tmp files should be created on your platform   None None 9_ We need to record what modules and packages we have loaded, so if we read a .hi file that wants to load something already loaded, we can safely ignore that request. We're in the IO monad anyway, so we can add some extra state of our own.The state is a FiniteMap String (Module,Int) (a hash of package/object names to Modules and how many times they've been loaded).(It also contains the package.conf information, so that if there is a package dependency we can find it correctly, even if it has a non-standard path or name, and if it isn't an official package (but rather one provided via -package-conf). This is stored as a FiniteMap PackageName PackageConfig. The problem then is whether a user's package.conf, that uses the same package name as an existing GHC package, should be allowed, or should shadow a library package? I don't know, but I'm inclined to have the GHC package shadow the user's package.This idea is based on Hampus Ram's dynamic loadery dependency tracking system. He uses state to record dependency trees to allow clean unloading and other fun. This is quite cool. We're just using state to make sure we don't load the same package twice. Implementing the full dependency tree idea would be nice, though not fully necessary as we have the dependency information store in .hi files, unlike in hram's loader.#apply f" to the loaded objects Env, apply f to the package.conf FM locks up the MVar_ so you can't recursively call a function inside a with any -Env function. Nice and threadsafe+0insert a loaded module name into the environment,\remove a module name from the environment. Returns True if the module was actually removed.-+insert a list of module names all in one go.#is a module/package already loaded?0!Set the dependencies of a Module.1;Get module dependencies. Nothing if none have been recored.2'Unrecord a module from the environment.3Insert a single package.conf (containing multiple configs) means: create a new FM. insert packages into FM. add FM to end of list of FM stored in the environment.4add a new FM for the package.conf to the list of existing ones; if a package occurs multiple times, pick the one with the higher version number as the default (e.g., important for base in GHC 6.12)5ggenerate a PkgEnv from the system package.conf The path to the default package.conf was determined by  configure This imposes a constraint that you must build your plugins with the same ghc you use to build hs-plugins. This is reasonable, we feel."#$%&'()*+,-./0123456789:;<="#$%&'()*+,-./012;<=3478956:None OX>)parse a file (as a string) as Haskell src?pretty print haskell srcdoesn't handle operators with # at the end. i.e. unsafeCoerce#@mergeModules : generate a full Haskell src file, give a .hs config file, and a stub to take default syntax and decls from. Mostly we just ensure they don't do anything bad, and that the names are correct for the module.Transformations:*. Take src location pragmas from the conf file (1st file) . Use the template's (2nd argument) module name . Only use export list from template (2nd arg) . Merge top-level decls . need to force the type of the plugin to match the stub, overwriting any type they supply.A replace Module name with String.merge import declarations:8ensure that the config file doesn't import the stub nameCmerge import lists uniquely, and when they match, merge their declsTODO * we don't merge imports of the same module from both files. We should, and then merge the decls in their import list * rename args, too confusing.5quick fix: strip all type signatures from the source.merge top-level declarationszRemove decls found in template, using those from the config file. Need to sort decls by types, then decls first, in both.aCould we write a pass to handle editor, foo :: String ? We must keep the type from the template.BParsing option pragmas.xThis is not a type checker. If the user supplies bogus options, they'll get slightly mystical error messages. Also, we want( to handle -package options, and other static flags. This is more than GHC.GHC user's guide :  OPTIONS pragmas are only looked for at the top of your source files, up to the first (non-literate,non-empty) line not containing OPTIONS. Multiple OPTIONS pragmas are recognised.6based on getOptionsFromSource(), in main/DriverUtil.hs> module name haskell srcabstract syntaxB input srcnormal options, global options>?@AB>@?BASafe Y?EFEFNone VfG$return the Z-Encoding of the string.5Stolen from GHC. Use -package ghc as soon as possibleIusefulJwriteFile for Handles openTempFile.System.IO.openTempFile uses undesirable characters in its filenames, which breaks e.g. merge and other functions that try to compile Haskell source. Sadly, this means we must provide our own secure temporary file facility.Like ), but opens the file in binary mode. See  for more comments.Like ', but uses the default file permissionsLike ', but uses the default file permissionsKUcreate a new temp file, returning name and handle. bit like the mktemp shell utilityMvGet a new temp file, unique from those in /tmp, and from those modules already loaded. Very nice for merge/eval uses.mWill run for a long time if we can't create a temp file, luckily mkstemps gives us a pretty big search spaceR /,  . : join two path componentsS /,  . : join two path componentsT /,  . : join two path componentsU /,  . : join two path componentsVJdirname : return the directory portion of a file path if null, return "."W0basename : return the filename portion of a pathY%work out the mod name from a filepathZ%Changes the extension of a file path.[The [ function is the opposite of \F. It joins a file name and an extension to form a complete file path.The general rule is: Qfilename `joinFileExt` ext == path where (filename,ext) = splitFileExt path\Split the path into file name and extension. If the file doesn't have extension, the function will return empty string. The extension doesn't include a leading period. Examples: splitFileExt "foo.ext" == ("foo", "ext") splitFileExt "foo" == ("foo", "") splitFileExt "." == (".", "") splitFileExt ".." == ("..", "") splitFileExt "foo.bar."== ("foo.bar.", "")hChecks whether the character is a valid path separator for the host platform. The valid character is a  but since the Windows operating system also accepts a slash ("/") since DOS 2, the function checks for it on this platform, too.]3return the object file, given the .conf file i.e. homedons foo.rc -> homedonsfoo.o3we depend on the suffix we are given having a lead _is file1 newer than file2?<needs some fixing to work with 6.0.x series. (is this true?)QfileExist still seems to throw exceptions on some platforms: ia64 in particular..invarient : we already assume the first file, a, exists%Directory in which to create the fileFile name prefix. If the prefix is "fooie", the full name will be "fooie" followed by six random alphanumeric characters followed by, if given, the suffix. Should not contain any path separator characters.EFile name suffix. Should not contain any path separator characters.ZThe path information to modify.rThe new extension (without a leading period). Specify an empty string to remove an existing extension from path.2A string containing the modified path information.GHIJKLMNOPQRSTUVWXYZ[\]^_`abHJMNOPQKL]^XYZ[\bVWRSTU_`aGIR6S6None >cConvience synonymd A list of String argumentseZMerging may be avoided if the source files are older than an existing merged result. The  MergeCodeO type indicates whether merging was performed, or whether it was unneccessary.f/An equivalent status for the preprocessor phasegthe merge was successfulh failure, and any errors returnediThe MakeCode type is used when compilation is successful, to distinguish two cases: * The source file needed recompiling, and this was done * The source file was already up to date, recompilation was skippedjrecompilation was performedkrecompilation was not requiredlThe  MakeStatus type represents success or failure of compilation. Compilation can fail for the usual reasons: syntax errors, type errors and the like. The  MakeFailureC constructor returns any error messages produced by the compiler.  MakeSuccess returns a MakeCode2 value, and the path to the object file produced.mcompilation was successfulncompilation failedo@One-shot unconditional compilation of a single Haskell module. make+ behaves like 'ghc -c'. Extra arguments to  may be passed in the args9 parameter, they will be appended to the argument list. makeA always recompiles its target, whether or not it is out of date.A side-effect of calling o is to have GHC produce a .hia file containing a list of package and objects that the source depends on. Subsequent calls to loadj will use this interface file to load module and library dependencies prior to loading the object itself.pp@ recursively compiles any dependencies it can find using GHC's --makeD flag. Dependencies will be recompiled only if they are visible to D -- this may require passing appropriate include path flags in the args parameter. p1 takes the top-level file as the first argument.qThis is a variety of o that first calls wn to combine the plugin source with a syntax stub. The result is then compiled. This is provided for EDSL authors who wish to add extra syntax to a user's source. It is important to note that the module and types from the second file argument are used to override any of those that appear in the first argument. For example, consider the following source files: !module A where a :: Integer a = 1and module B where a :: IntCalling  makeWith A B []\ will merge the module name and types from module B into module A, generating a third file: e{-# LINE 1 "A.hs" #-} module MxYz123 where {-# LINE 3 "B.hs" #-} a :: Int {-# LINE 4 "A.hs" #-} a = 1r hasChanged returns Trued if the module or any of its dependencies have older object files than source files. Defaults to True# if some files couldn't be located.tt is like p, but rather than relying on  ghc --make, we explicitly check a module's dependencies using our internal map of module dependencies. Performance is thus better, and the result is more accurate.vLower-level than o. Compile a .hs file to a .o file If the plugin needs to import an api (which should be almost everyone) then the ghc flags to find the api need to be provided as argumentswMerge to source files into a temporary file. If we've tried to merge these two stub files before, then reuse the module name (helps recompilation checking)4The merging operation is extremely useful for providing extra default syntax. An EDSL user then need not worry about declaring module names, or having required imports. In this way, the stub file can also be used to provide syntax declarations that would be inconvenient to require of the plugin author.w will include any import and export declarations written in the stub, as well as any module name, so that plugin author's need not worry about this compulsory syntax. Additionally, if a plugin requires some non-standard library, which must be provided as a -package< flag to GHC, they may specify this using the non-standard  GLOBALOPTIONS pragma. Options specified in the source this way will be added to the command line. This is useful for users who wish to use GHC flags that cannot be specified using the conventional OPTIONSW pragma. The merging operation uses the parser hs-plugins was configured with, either   3 or the HSX parser, to parse Haskell source files.xx behaves like w8, but we can specify the file in which to place output.yy behaves like w+, but lets you specify a target directory.zmakeClean : assuming we some element of [f.hs,f.hi,f.o], remove the .hi and .o components. Silently ignore any missing components. /Does not remove .hs files/. To do that use {6. This would be useful for merged files, for example.q a src filea syntax stub fileany required argspath to an object filesrcany compiler args!do our own recompilation checkingvpath to .hs sourcepath to object fileany extra cmd line flagscdefghijklmnopqrstuvwxyz{lmnijkopqrstufghedcwxyz{vfghijklmnNone DAyThe  LoadStatusc type encodes the return status of functions that perform dynamic loading in a type isomorphic to . Failure returns a list of error strings, success returns a reference to a loaded module, and the Haskell value corresponding to the symbol that was indexed.: is the basic interface to the dynamic loader. A call to  imports a single object file into the caller's address space, returning the value associated with the symbol requested. Libraries and modules that the requested module depends upon are loaded and linked in turn.The first argument is the path to the object file to load, the second argument is a list of directories to search for dependent modules. The third argument is a list of paths to user-defined, but unregistered,  package.conf files. The @ argument is the symbol name of the value you with to retrieve.The value returned must be given an explicit type signature, or provided with appropriate type constraints such that Haskell compiler can determine the expected type returned by 0, as the return type is notionally polymorphic.Example: do mv <- load "Plugin.o" ["api"] [] "resource" case mv of LoadFailure msg -> print msg LoadSuccess _ v -> return vELike load, but doesn't want a package.conf arg (they are rarely used)A work-around for Dynamics. The keys used to compare two TypeReps are somehow not equal for the same type in hs-plugin's loaded objects. Solution: implement our own dynamics...The problem with dynload is that it requires the plugin to export a value that is a Dynamic (in our case a (TypeRep,a) pair). If this is not the case, we core dump. Use pdynload if you don't trust the user to supply you with a Dynamic!The super-replacement for dynloadUse GHC at runtime so we get staged type inference, providing full power dynamics, *on module interfaces only*. This is quite suitable for plugins, of coures :)8TODO where does the .hc file go in the call to build() ?GLike pdynload, but you can specify extra arguments to the typechecker.,run the typechecker over the constraint fileProblem: if the user depends on a non-auto package to build the module, then that package will not be in scope when we try to build the module, when performing . Normally make() will handle this (as it takes extra ghc args). pdynload ignores these, atm -- but it shouldn't. Consider a pdynload() that accepts extra -package flags?bAlso, pdynload() should accept extra in-scope modules. Maybe other stuff we want to hack in here.cunload a module (not its dependencies) we have the dependencies, so cascaded unloading is possibleonce you unload it, you can't  it again, you have to 0 it. Cause we don't unload all the dependenciesaunload a module and its dependencies we have the dependencies, so cascaded unloading is possiblethis will be nice for panTHeon, needs thinking about the interface reload a single object file. don't care about depends, assume they are loaded. (should use state to store all this)assumes you've already done a should factor the codeCall the initLinker function first, before calling any of the other functions in this module - otherwise you'll get unresolved symbols.HLoad a function from a module (which must be loaded and resolved first)._Loads a function from a package module, given the package name, module name and symbol name.^Load a GHC-compiled Haskell vanilla object file. The first arg is the path to the object fileWe make it idempotent to stop the nasty problem of loading the same .o twice. Also the rts is a very special package that is already loaded, even if we ask it to be loaded. N.B. we should insert it in the list of known packages.NB the environment stores the *full path* to an object. So if you want to know if a module is already loaded, you need to supply the *path* to that object, not the name.%NB -- let's try just the module name.loadObject loads normal .o objs, and packages too. .o objs come with a nice canonical Z-encoded modid. packages just have a simple name. Do we want to ensure they won't clash? Probably.the second argument to loadObject is a string to use as the unique identifier for this object. For normal .o objects, it should be the Z-encoded modid from the .hi file. For archives/packages, we can probably get away with the package nameJload a single object. no dependencies. You should know what you're doing.Load a generic .o file, good for loading C objects. You should know what you're doing.. Returns a fairly meaningless iface value.)Resolve (link) the modules loaded by the  function.Unload a modulefrom ghci/ObjLinker.cLoad a .so type object file.~Load a -package that we might need, implicitly loading the cbits too The argument is the name of package (e.g. "concurrent")How to find a package is determined by the package.conf info we store in the environment. It is just a matter of looking it up.$Not printing names of dependent pkgspUnload a -package, that has already been loaded. Unload the cbits too. The argument is the name of the package.May need to check if it exists.BNote that we currently need to unload everything. grumble grumble.uWe need to add the version number to the package name with 6.4 and over. "yi-0.1" for example. This is a bug really.load a package using the given package.conf to help TODO should report if it doesn't actually load the package, instead of mapM_ doing nothing like above.module dependency loadingggiven an Foo.o vanilla object file, supposed to be a plugin compiled by our library, find the associated .hi file. If this is found, load the dependencies, packages first, then the modules. If it doesn't exist, assume the user knows what they are doing and continue. The linker will crash on them anyway. Second argument is any include paths to search inToDo problem with absolute and relative paths, and different forms of relative paths. A user may cause a dependency to be loaded, which will search the incpaths, and perhaps find "./Foo.o". The user may then explicitly load "Foo.o". These are the same, and the loader should ignore the second load request. However, isLoaded will say that "Foo.o" is not loaded, as the full string is used as a key to the modenv fm. We need a canonical form for the keys -- is basename good enough?Nice interface to .hi parser object fileany include pathslist of package.conf pathssymbol to find object fileany include pathssymbol to findobject to load include paths package confsAPI typesymbolobject to loadinclude paths for loadingany extra package.conf files)extra arguments to ghc, when typechecking expected typesymbol to loadThe module the value is inSymbol name of valueThe value you want'Package name, including version number. Module nameSymbol to lookup in the module None B8cdefghijklmnopqrstuvwxyz{ None C< None tb_ provides a typesafe (to a limit) form of runtime evaluation for Haskell -- a limited form of runtime metaprogramming. The  argument to 6 is a Haskell source fragment to evaluate at rutime. impsI are a list of module names to use in the context of the compiled value.The value returned by  is constrained to be  -- meaning we can perform a limited runtime typecheck, using the w function. One consequence of this is that the code must evaluate to a monomorphic value (which will be wrapped in a ).+If the evaluated code typechecks under the % constraints, 'Just v' is returned.  indicates typechecking failed. Typechecking may fail at two places: when compiling the argument, or when typechecking the splice point.  resembles a metaprogramming run operator for closed source fragments.\To evaluate polymorphic values you need to wrap them in data structures using rank-N types. Examples: bdo i <- eval "1 + 6 :: Int" [] :: IO (Maybe Int) when (isJust i) $ putStrLn (show (fromJust i)) is a variety of  with all the internal hooks available. You are able to set any extra arguments to the compiler (for example, optimisation flags) or dynamic loader, as well as having any errors returned in an  type.Sometimes when constructing string fragments to evaluate, the programmer is able to provide some other constraint on the evaluated string, such that the evaluated expression will be typesafe, without requiring a F constraint. In such cases, the monomorphic restriction is annoying.  removes any splice-point typecheck, with an accompanying obligation on the programmer to ensure that the fragment evaluated will be typesafe at the point it is spliced.IAn example of how to do this would be to wrap the fragment in a call to J. The augmented fragment would then be checked when compiled to return a `, and the programmer can rely on this, without requiring a splice-point typecheck, and thus no  restriction.INote that if you get the proof wrong, your program will likely segfault.Example: edo s <- unsafeEval "map toUpper \"haskell\"" ["Data.Char"] when (isJust s) $ putStrLn (fromJust s) is a form of  with all internal hooks exposed. This is useful for application wishing to return error messages to users, to specify particular libraries to link against and so on.% is a helper function for converting s of names and values into Haskell code. It relies on the assumption of names and values into Haskell code. It relies on the assumption that the passed values' Show instances produce valid Haskell literals (this is true for all Prelude types)._Return a compiled value's type, by using Dynamic to get a representation of the inferred type.code to compile any importsextra make flags(package.confs) for load"include paths load is to search in*either errors, or maybe a well typed valuecode to compile any imports make flags(package.confs) for load"include paths load is to search inBNone uB !"##$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrs*tuvwxyz{|}~       #plugins-1.5.7-liVkAqbm9AEVBOAkEsBLJSystem.Plugins.ParserSystem.Plugins.ConstsSystem.Plugins.LoadTypesSystem.Plugins.EnvSystem.Plugins.ProcessSystem.Plugins.UtilsSystem.Plugins.MakeSystem.Plugins.LoadSystem.Eval.UtilsSystem.Eval.HaskellLanguageHaskellSystem.PluginsDataMap System.Eval*haskell-src-1.0.2.0-4OFUdEuN1o5IwIkhXVhwUMLanguage.Haskell.SyntaxHsModuletopghcghcLibraryPath sysPkgConf sysPkgSuffixobjSufhiSufhsSufdllSuf sysPkgPrefixprefixUnderscoretmpDirObjTypeVanillaSharedModulepathmnamekindifacekey PackageConfErrorsTypeSymbolKeyObjectPackage $fEqModule $fOrdModule $fEqObjTypeenv withModEnv withDepEnv withPkgEnvs withMerged modifyModEnv modifyDepEnv modifyPkgEnv modifyMerged addModulermModule addModulesisLoadedloaded addModuleDeps getModuleDeps rmModuleDeps addPkgConfuniongrabDefaultPkgConfreadPackageConf addStaticPkg isStaticPkg rmStaticPkg lookupPkgisMerged lookupMergedaddMergeparsepretty mergeModulesreplaceModName parsePragmas$fSynEqHsImportDecl $fSynEqHsDeclexecpopen EncodedStringArgpanichWritemkTempmkTempInmkUnique hMkUnique mkUniqueIn hMkUniqueInfindFile<.><+><>dirnamebasename dropSuffixmkModid changeFileExt joinFileExt splitFileExt replaceSuffix outFilePathnewerencodedecode isSublistOfArgs MergeCode MergeStatus MergeSuccess MergeFailureMakeCodeReCompNotReq MakeStatus MakeSuccess MakeFailuremakemakeAllmakeWith hasChanged hasChanged' recompileAll recompileAll'buildmergemergeTo mergeToDir makeClean makeCleaner $fEqMakeCode$fShowMakeCode$fEqMergeStatus$fShowMergeStatus$fEqMakeStatus$fShowMakeStatus LoadStatus LoadSuccess LoadFailureloadload_dynloadpdynload pdynload_unload unloadAllreload initLinker loadFunction loadFunction_loadPackageFunction loadModule loadRawObject resolveObjs loadShared loadPackage unloadPackageloadPackageWith getImportsImportsymbolescapegetPaths mkUniqueWithcleanupevaleval_ unsafeEval unsafeEval_ mkHsValuestypeOfModEnvHSLibStaticDynamic LibrarySpecDLLDLLPathmImpsmDeclPragmaOptionGlobalSynEq=~!~ openTempFileopenBinaryTempFilebaseGHC.IO.Handle.FDopenBinaryFile"openTempFileWithDefaultPermissions(openBinaryTempFileWithDefaultPermissionsisPathSeparatorfilepath-1.4.1.2System.FilePath.Posix pathSeparatorGHC.Base.OpenNewFileResultNewFileCreated FileExists OpenNewErrorrawMake Data.EitherEitherunify loadObject unloadObj loadDepends Control.MonadguardjoinMonadfail>>=>>returnFunctorfmapData.TraversablemapMsequenceMaybeNothingJust=<< Data.Maybemaybe Data.Foldable sequence_ MonadPlusmplusmzerowhenliftMliftM2apisJust isNothing fromMaybe maybeToList listToMaybe catMaybesmapMaybe Data.FunctorvoidfilterMfoldMunlessmfilter<$!> replicateM_ replicateMfoldM_ zipWithM_zipWithM mapAndUnzipMforever<=<>=>forMmsumforM_mapM_fromJustliftM5liftM4liftM3StringData.Typeable.InternalTypeable Data.DynamicGHC.Showshow