yp      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  Safe-InferredNone*parse a file (as a string) as Haskell src pretty print haskell src doesn't handle operators with '#' at the end. i.e. unsafeCoerce# CmergeModules : generate a full Haskell src file, give a .hs config C 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 5 . 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. !replace Module name with String. merge import declarations: $ ensure that the config file doesn't import the stub name J * merge import lists uniquely, and when they match, merge their decls  TODO * we don'5t merge imports of the same module from both files. ? We should, and then merge the decls in their import list $ * rename args, too confusing. 6quick fix: strip all type signatures from the source. merge top-level declarations BRemove decls found in template, using those from the config file. 9 Need to sort decls by types, then decls first, in both. 8Could we write a pass to handle editor, foo :: String ? * We must keep the type from the template. Parsing option pragmas. @This is not a type checker. If the user supplies bogus options,  they'2ll 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 :  B OPTIONS pragmas are only looked for at the top of your source = files, up to the first (non-literate,non-empty) line not A containing OPTIONS. Multiple OPTIONS pragmas are recognised. (based on getOptionsFromSource(), in main/DriverUtil.hs  module name  haskell src abstract syntax  input src normal options, global options None      None=path to *build* dir, used by eval() for testing the examples what is ghc called? path to standard ghc libraries %name of the system package.conf file "This code is from runtime_loader: ) The extension used by system modules. #>The prefix used by system modules. This, in conjunction with  systemModuleExtension., will result in a module filename that looks  like "HSconcurrent.o" $'_' on a.out, and Darwin %DDefine tmpDir to where tmp files should be created on your platform  !"#$%  !"#$%  !"#$%  !"#$%None BWe need to record what modules and packages we have loaded, so if D 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. 8The state is a FiniteMap String (Module,Int) (a hash of  package//object names to Modules and how many times they've been  loaded). EIt 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 G rather one provided via -package-conf). This is stored as a FiniteMap > PackageName PackageConfig. The problem then is whether a user's B package.conf, that uses the same package name as an existing GHC D 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 loader dependency D tracking system. He uses state to record dependency trees to allow 6 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 E 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 6 inside a with any -Env function. Nice and threadsafe /1insert a loaded module name into the environment 0?remove a module name from the environment. Returns True if the  module was actually removed. 1,insert a list of module names all in one go 2 is a module/package already loaded? 4"Set the dependencies of a Module. 5<Get module dependencies. Nothing if none have been recored. 6(Unrecord a module from the environment. 7BInsert a single package.conf (containing multiple configs) means: G create a new FM. insert packages into FM. add FM to end of list of FM  stored in the environment. 8]add 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) 9/generate a PkgEnv from the system package.conf 8 The path to the default package.conf was determined by  configure E This imposes a constraint that you must build your plugins with the D same ghc you use to build hs-plugins. This is reasonable, we feel. :&'()*+,-./0123456789:;<=>?@&'()*+,-./0123456789:;<=>?@&'()*+,-./0123456>?@78;<9:=6&'()*+,-./0123456789:;<=>?@NoneA%return the Z-Encoding of the string. 6Stolen from GHC. Use -package ghc as soon as possible Cuseful DwriteFile for Handles E mkstemps. AWe use the Haskell version now... it is faster than calling into  mkstemps(3). 3create a new temp file, returning name and handle. # bit like the mktemp shell utility G*Get a new temp file, unique from those in /tmp, and from those , modules already loaded. Very nice for merge/ eval uses. "Will run for a long time if we can't create a temp file, luckily - mkstemps gives us a pretty big search space L /,  . : join two path components M /,  . : join two path components N /,  . : join two path components O /,  . : join two path components P6dirname : return the directory portion of a file path  if null, return . Q1basename : return the filename portion of a path S&work out the mod name from a filepath T&Changes the extension of a file path. UThe U function is the opposite of V. E It joins a file name and an extension to form a complete file path. The general rule is: $ filename `joinFileExt` ext == path  where ( (filename,ext) = splitFileExt path V>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.", "") DChecks whether the character is a valid path separator for the host $ platform. The valid character is a  pathSeparator but since the Windows ( operating system also accepts a slash ("/") since DOS 2, the function & checks for it on this platform, too. W-return the object file, given the .conf file  i.e. homedons foo.rc -> homedonsfoo.o 3we depend on the suffix we are given having a lead  Yis file1 newer than file2? =needs some fixing to work with 6.0.x series. (is this true?) EfileExist still seems to throw exceptions on some platforms: ia64 in  particular. .invarient : we already assume the first file, a , exists #ABCDEFGHIJKLMNOPQRST The path information to modify. .The new extension (without a leading period). / Specify an empty string to remove an existing  extension from path. 3A string containing the modified path information. UVWXYZ[\ABCDEFGHIJKLMNOPQRSTUVWXYZ[\BDGHIJKEFWXRSTUV\PQLMNOYZ[AC#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\None]Convience synonym ^ A list of String arguments _=Merging may be avoided if the source files are older than an  existing merged result. The  MergeCode type indicates whether 8 merging was performed, or whether it was unneccessary. `0An equivalent status for the preprocessor phase a!failure, and any errors returned bthe merge was successful cThe MakeCode1 type is used when compilation is successful, to  distinguish two cases: : * The source file needed recompiling, and this was done F * The source file was already up to date, recompilation was skipped drecompilation was not required erecompilation was performed fThe  MakeStatus4 type represents success or failure of compilation. A Compilation can fail for the usual reasons: syntax errors, type  errors and the like. The  MakeFailure constructor returns any error $ messages produced by the compiler.  MakeSuccess returns a MakeCode 2 value, and the path to the object file produced. gcompilation failed hcompilation was successful i?One-shot unconditional compilation of a single Haskell module.  make behaves like 'ghc -c'. Extra arguments to  may be passed  in the args8 parameter, they will be appended to the argument list.  make; always recompiles its target, whether or not it is out of  date. A side-effect of calling i is to have GHC produce a .hi file F containing a list of package and objects that the source depends on.  Subsequent calls to load& will use this interface file to load E module and library dependencies prior to loading the object itself. jj9 recursively compiles any dependencies it can find using  GHC's --make8 flag. Dependencies will be recompiled only if they are  visible to 6 -- this may require passing appropriate include path  flags in the args parameter. j takes the top-level file as  the first argument. kThis is a variety of i that first calls q to B combine the plugin source with a syntax stub. The result is then C 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 E module and types from the second file argument are used to override G any of those that appear in the first argument. For example, consider  the following source files:   module A where  a :: Integer  a = 1 and   module B where  a :: Int Calling  makeWith A B []& will merge the module name and types 7 from module B into module A, generating a third file:  {-# LINE 1 "A.hs" #-}  module MxYz123 where  {-# LINE 3 "B.hs" #-}  a :: Int  {-# LINE 4 "A.hs" #-}  a = 1 l hasChanged returns True if the module or any of its F dependencies have older object files than source files. Defaults to  True if some files couldn't be located. nn is like j, but rather than relying on   ghc --make, we explicitly check a module's dependencies using our F internal map of module dependencies. Performance is thus better, and  the result is more accurate. pLower-level than i". Compile a .hs file to a .o file > If the plugin needs to import an api (which should be almost E everyone) then the ghc flags to find the api need to be provided as  arguments q2Merge to source files into a temporary file. If we' ve tried to F merge these two stub files before, then reuse the module name (helps  recompilation checking) FThe merging operation is extremely useful for providing extra default A syntax. An EDSL user then need not worry about declaring module D names, or having required imports. In this way, the stub file can ; also be used to provide syntax declarations that would be 0 inconvenient to require of the plugin author. q< will include any import and export declarations written in < the stub, as well as any module name, so that plugin author's need C not worry about this compulsory syntax. Additionally, if a plugin A requires some non-standard library, which must be provided as a  -package; flag to GHC, they may specify this using the non-standard   GLOBALOPTIONS3 pragma. Options specified in the source this way F will be added to the command line. This is useful for users who wish B to use GHC flags that cannot be specified using the conventional  OPTIONS: pragma. The merging operation uses the parser hs-plugins  was configured with, either    or the HSX parser, to  parse Haskell source files. rr behaves like q!, but we can specify the file in  which to place output. ss behaves like q , but lets you specify a target  directory. t6makeClean : 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 u. This would be ' useful for merged files, for example. ]^_`abcdefghijk a src file a syntax stub file any required args path to an object file lmnosrc any compiler args "do our own recompilation checking ppath to .hs source path to object file any extra cmd line flags qrstu]^_`abcdefghijklmnopqrstufhgcedijklmno`ba_^]qrstup]^_`bacedfhgijklmnopqrstuNonevThe  LoadStatus2 type encodes the return status of functions that 1 perform dynamic loading in a type isomorphic to  . Failure C returns a list of error strings, success returns a reference to a G loaded module, and the Haskell value corresponding to the symbol that  was indexed. zz9 is the basic interface to the dynamic loader. A call to  z- imports a single object file into the caller's address space, E returning the value associated with the symbol requested. Libraries C and modules that the requested module depends upon are loaded and  linked in turn. FThe first argument is the path to the object file to load, the second D 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 0 symbol name of the value you with to retrieve. @The value returned must be given an explicit type signature, or G provided with appropriate type constraints such that Haskell compiler - can determine the expected type returned by z, as the return ! type is notionally polymorphic.  Example: 0 do mv <- load "Plugin.o" ["api"] [] "resource"  case mv of % LoadFailure msg -> print msg $ LoadSuccess _ v -> return v {Like load, but doesn'1t want a package.conf arg (they are rarely used) |FA work-around for Dynamics. The keys used to compare two TypeReps are 1 somehow not equal for the same type in hs-plugin's loaded objects. ) Solution: implement our own dynamics... BThe problem with dynload is that it requires the plugin to export E a value that is a Dynamic (in our case a (TypeRep,a) pair). If this 7 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 dynload CUse GHC at runtime so we get staged type inference, providing full E power dynamics, *on module interfaces only*. This is quite suitable  for plugins, of coures :) 9TODO where does the .hc file go in the call to build() ? ~:Like pdynload, but you can specify extra arguments to the  typechecker. -run the typechecker over the constraint file @Problem: if the user depends on a non-auto package to build the E module, then that package will not be in scope when we try to build  the module, when performing #. Normally make() will handle this E (as it takes extra ghc args). pdynload ignores these, atm -- but it  shouldn'<t. Consider a pdynload() that accepts extra -package flags? 7Also, pdynload() should accept extra in-scope modules. , Maybe other stuff we want to hack in here. 'unload a module (not its dependencies) = we have the dependencies, so cascaded unloading is possible once you unload it, you can't z it again, you have to   it. Cause we don't unload all the dependencies %unload a module and its dependencies = we have the dependencies, so cascaded unloading is possible Cthis will be nice for panTHeon, needs thinking about the interface ! reload a single object file. don'"t care about depends, assume they 2 are loaded. (should use state to store all this)  assumes you've already done a z should factor the code DCall the initLinker function first, before calling any of the other ) functions in this module - otherwise you'll get unresolved symbols. ILoad 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. 1Load a GHC-compiled Haskell vanilla object file. . The first arg is the path to the object file DWe make it idempotent to stop the nasty problem of loading the same B .o twice. Also the rts is a very special package that is already E loaded, even if we ask it to be loaded. N.B. we should insert it in  the list of known packages. BNB the environment stores the *full path* to an object. So if you D 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. EloadObject loads normal .o objs, and packages too. .o objs come with E a nice canonical Z-encoded modid. packages just have a simple name.  Do we want to ensure they won't clash? Probably. Cthe second argument to loadObject is a string to use as the unique E identifier for this object. For normal .o objects, it should be the 0 Z-encoded modid from the .hi file. For archives/packages, we can ) probably get away with the package name ?load a single object. no dependencies. You should know what you're  doing. 4Load 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 module  from ghci/ ObjLinker.c Load a .so type object file. ELoad a -package that we might need, implicitly loading the cbits too , The argument is the name of package (e.g. " concurrent") FHow 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 pkgs BUnload 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. CNote that we currently need to unload everything. grumble grumble. CWe 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. 4load 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 loading Egiven an Foo.o vanilla object file, supposed to be a plugin compiled F by our library, find the associated .hi file. If this is found, load @ the dependencies, packages first, then the modules. If it doesn't D exist, assume the user knows what they are doing and continue. The B linker will crash on them anyway. Second argument is any include  paths to search in FToDo problem with absolute and relative paths, and different forms of C 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 C should ignore the second load request. However, isLoaded will say  that Foo.o7 is not loaded, as the full string is used as a key to E the modenv fm. We need a canonical form for the keys -- is basename  good enough? Nice interface to .hi parser %vwxyz object file any include paths list of package.conf paths symbol to find { object file any include paths symbol to find |}object to load include paths package confs  API type symbol ~object to load include paths for loading any extra package.conf files *extra arguments to ghc, when typechecking expected type symbol to load The module the value is in Symbol name of value The value you want (Package name, including version number.  Module name Symbol to lookup in the module  vwxyz{|}~vxwz{|}~ y#vxwyz{|}~ None8 ]^_`abcdefghijklmnopqrstuvwxyz{|}~ None;      None= provides a typesafe (to a limit) form of runtime evaluation " for Haskell -- a limited form of runtime metaprogramming. The   argument to * is a Haskell source fragment to evaluate  at rutime. imps5 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  |9 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. F 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: 2 do i <- eval "1 + 6 :: Int" [] :: IO (Maybe Int) 3 when (isJust i) $ putStrLn (show (fromJust i))  is a variety of  with all the internal hooks D available. You are able to set any extra arguments to the compiler A (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 F programmer is able to provide some other constraint on the evaluated F string, such that the evaluated expression will be typesafe, without  requiring a , constraint. In such cases, the monomorphic  restriction is annoying.  removes any splice-point A typecheck, with an accompanying obligation on the programmer to E ensure that the fragment evaluated will be typesafe at the point it  is spliced. EAn example of how to do this would be to wrap the fragment in a call  to =. The augmented fragment would then be checked when compiled  to return a /, and the programmer can rely on this, without 1 requiring a splice-point typecheck, and thus no   restriction. ?Note that if you get the proof wrong, your program will likely  segfault.  Example: < do s <- unsafeEval "map toUpper \"haskell\"" ["Data.Char"] , when (isJust s) $ putStrLn (fromJust s)  is a form of  with all internal hooks A exposed. This is useful for application wishing to return error D messages to users, to specify particular libraries to link against  and so on. % is a helper function for converting s G of names and values into Haskell code. It relies on the assumption of F 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 imports extra make flags (package.confs) for load #include paths load is to search in +either errors, or maybe a well typed value code to compile  any imports  make flags (package.confs) for load #include paths load is to search in A      NoneA       !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklm%nopqrstuvwxyz{|}~  ]      !"#$%&'()*+,-./012 3 4 56plugins-1.5.4.0System.Plugins.ParserSystem.Plugins.ProcessSystem.Plugins.LoadTypesSystem.Plugins.ConstsSystem.Plugins.EnvSystem.Plugins.UtilsSystem.Plugins.MakeSystem.Plugins.LoadSystem.Eval.UtilsSystem.Eval.HaskellLanguageHaskellSystem.PluginsDataMap System.Evalhaskell-src-1.0.1.5Language.Haskell.SyntaxHsModuleexecpopenparsepretty mergeModulesreplaceModName parsePragmasObjTypeSharedVanillaModulepathmnamekindifacekey PackageConfErrorsTypeSymbolKeyPackageObjecttopghcghcLibraryPath sysPkgConf sysPkgSuffixobjSufhiSufhsSufdllSuf sysPkgPrefixprefixUnderscoretmpDirenv withModEnv withDepEnv withPkgEnvs withMerged modifyModEnv modifyDepEnv modifyPkgEnv modifyMerged addModulermModule addModulesisLoadedloaded addModuleDeps getModuleDeps rmModuleDeps addPkgConfuniongrabDefaultPkgConfreadPackageConf addStaticPkg isStaticPkg lookupPkgisMerged lookupMergedaddMerge EncodedStringArgpanichWritemkTempmkTempInmkUnique hMkUnique mkUniqueIn hMkUniqueInfindFile<.><+><>dirnamebasename dropSuffixmkModid changeFileExt joinFileExt splitFileExt replaceSuffix outFilePathnewerencodedecode isSublistOfArgs MergeCode MergeStatus MergeFailure MergeSuccessMakeCodeNotReqReComp MakeStatus MakeFailure MakeSuccessmakemakeAllmakeWith hasChanged hasChanged' recompileAll recompileAll'buildmergemergeTo mergeToDir makeClean makeCleaner LoadStatus LoadFailure LoadSuccess initLinkerloadload_dynloadpdynload pdynload_unload unloadAllreload loadFunction loadFunction_loadPackageFunction loadModule loadRawObject resolveObjs loadShared loadPackage unloadPackageloadPackageWith getImportsImportsymbolescapegetPaths mkUniqueWithcleanupevaleval_ unsafeEval unsafeEval_ mkHsValuestypeOf ProcessIDmImpsmDeclPragmaGlobalOptionSynEq=~!~ matchPragma remove_spaces prefixMatchmaybePrefixMatch$fSynEqHsImportDecl $fSynEqHsDecl $fEqModule $fOrdModuleModEnv PackageConfig PackageNameHSLibDynamicStatic LibrarySpecDLLPathDLLEnvPkgEnvsMergeEnv StaticPkgEnvPkgEnvDepEnv FiniteMapemptyFMaddToFM addWithFM delFromFMlookupFMwithStaticPkgEnvmodifyStaticPkgEnv lockAndWriteclassifyLdInputmkSOName mkDynPkgName lookupPkg' packageName packageDepsisPathSeparatorbaseGHC.Base. unencodedChar decode_upper decode_lowerdecode_num_esc encode_ch decode_tuplerawMakerawMergerm_f readFile' Data.EitherEitherunify loadObject unloadObj loadDependsc_addDLL c_resolveObjs c_unloadObj c_loadObjc_lookupSymbolifaceModuleName readBinIface'mkTestloadFunction__ loadObject'fail>>=>>fmapreturn Control.MonadguardliftMMonadFunctor MonadPlus Data.MaybeMaybeNothingfoldMmfilterapliftM5liftM4liftM3liftM2unlesswhen replicateM_ replicateMfoldM_ zipWithM_zipWithM mapAndUnzipMjoinvoidforever<=<>=>msumforM_forMfilterMmapM_mapM sequence_sequence=<<mplusmzeromapMaybe catMaybes listToMaybe maybeToList fromMaybefromJust isNothingisJustmaybeJustStringData.Typeable.InternalTypeable Data.DynamicGHC.Showshowdynwrapidentwrap