gunzip -c all.nq.gz | grep 'node/kind" "package' > packages.nq
gunzip -c all.nq.gz | awk 'NR==FNR { a[$1]; next } /childof/{if ($3 in a) print $1}' packages.nq - > pkgchildren.txt
gunzip -c all.nq.gz | awk 'NR==FNR { a[$1]; next } /childof/{if ($3 in a) print $1" "$3}' pkgchildren.txt - | gzip - > topchildren.txt.gz
gunzip -c all.nq.gz | awk 'NR==FNR { a[$1]=$2; mx=FNR; next } (NR-mx==FNR) { b[$1] ; next } /kythe\/edge\/ref/{if (($1 in a) && ($3 in b)) print a[$1]" "$3}' <(gunzip -c topchildren.txt.gz) pkgchildren.txt - | uniq | gzip - > callgraph.txt.gz

GHC API lets you process Haskell sources, and (among other) specify code generation and linking level. For example:

  • (1) no codegen & no link
  • (2) bytecode generation & link in memory
  • (3) machine code generation & linking output binaries

For code analysis purposes, based on generating the typechecked AST, option (1) suffices most of the time. There are some situations in which it doesn't:

  • TemplateHaskell (TH) splice needs to execute code (at compile time) from an imported module: the imported module must be available in compiled form, so either (2) or (3) is needed. Example: in $([|$(foo)|]), foo will be evaluated at compile-time.
  • Code uses FFI imports. For this one would expect that (2) is needed (see checkCOrAsmOrLlvmOrInterp in TcForeign.hs), but actually unless it is used (say by TH, see below), even (1) works too (see the wrapper checkCg).
View GhcWrapper.hs
import GHC.Paths
import System.Posix.Process
import System.Environment
import System.IO
import Data.List (intercalate)
import Control.Monad (when)
lg = appendFile "/tmp/fake.lg" . (++ "\n")
main = do
# GHC wrapper for indexing Haskell packages.
# Note that variables INDEXER_OUTPUT_DIR and REALGHC are set outside this script.
log() {
echo "$1" >> "$INDEXER_OUTPUT_DIR/$PKG.log"
log "GHC $*"
/opt/kythe/tools/triples --graphstore ~/dev/ghc-vagrant/entries/gs > entries.all
cayley init -db leveldb -dbpath cdb
cayley load -db leveldb -dbpath cdb -quads=entries.all -alsologtostderr
View ghc8-ast.txt
=== Recursive function with type signature
A recursive call (with typesig) targets the polymorphic binding (vs the monomorphic one usually targeted).
Now there's a new ctor for this kind of function (AbsBindsSig), having only a poly-like binding exposed.
Caveat: the internal FunBind still refers the monomorphic binding. So it's a bit less obvious to make the connection.
View Sphinx.chs
module Sphinx where
import Data.Text (Text)
import Foreign (alloca, peek)
import Foreign.C.String (CString)
import Foreign.Ptr (Ptr, nullPtr)
-- TODO move utils
peekIntegral = fmap fromIntegral . peek
View Lib.hs
{-# LANGUAGE QuasiQuotes #-}
module Lib where
import NeatInterpolation
renderXmlRequest = [text|apple|]
# Need to install ffcast, and advisedly also xrectsel (on arch can do from AUR)
# Below command will let you select a region with the mouse, than stream it to ffmpeg.
# Many args magic (taken from SO), but allegedly it saves as lossless.
ffcast -s % ffmpeg -f x11grab -show_region 1 -framerate 20 -video_size %s -i %D+%c -codec:v huffyuv -vf crop="iw-mod(iw\\,2):ih-mod(ih\\,2)" out.avi
# Use ImageMagick to covert to gif - works great!
convert -set delay 5 -layers Optimize out.avi out.gif
View Lista.hs
data Lista = Megtobb Int Lista | Vege
uresLista :: Lista
uresLista = Vege
egyKetHa :: Lista
egyKetHa = Megtobb 1 (Megtobb 2 (Megtobb 3 Vege))
hossz :: Lista -> Int
hossz Vege = 0