Commit 8c859131 authored by Marc Coiffier's avatar Marc Coiffier
Browse files

Merge branch 'master' of git+ssh://git.coiffier.net/marc/curly into travis-tests

parents 0860b4f4 0e67df66
.*
public
curly/doc/bundle
woosh
grow
Curly_Test.hs
......@@ -3,18 +3,22 @@
name: curly-core
version: 0.7
-- synopsis:
synopsis: The core libraries for the Curly compiler.
-- description:
license: MIT
license-file: LICENSE
author: Marc Coiffier
maintainer: marc.coiffier@univ-grenoble-alpes.fr
-- copyright:
-- category:
category: Compilers
build-type: Simple
extra-source-files: ChangeLog.md sha256.c
cabal-version: >=1.10
flag paranoid
default: False
manual: True
library
exposed-modules:
Curly.Core,
......@@ -44,8 +48,9 @@ library
AllowAmbiguousTypes
LambdaCase
other-extensions: UndecidableInstances, ScopedTypeVariables, StandaloneDeriving, PatternSynonyms, ViewPatterns, TypeFamilies, CPP, RecursiveDo, GADTs, DeriveGeneric, OverloadedStrings, NoMonomorphismRestriction, DeriveDataTypeable, ExistentialQuantification, BangPatterns
build-depends: AES >=0.2 && <0.3,base >=4.9 && <4.10,base64-bytestring >=1.0 && <1.1,bytestring >=0.10 && <0.11,containers >=0.5 && <0.6,deepseq >=1.4 && <1.5,definitive-base >=2.6 && <2.7,definitive-filesystem >=2.1 && <2.2,definitive-network >=1.4 && <1.5,definitive-parser >=2.5 && <2.6,directory >=1.3 && <1.4,entropy >=0.3 && <0.4,hinotify >=0.3 && <0.4,network >=2.6 && <2.7,process >=1.4 && <1.5,zlib >=0.6 && <0.7
ghc-options: -Wall -Werror
build-depends: AES >=0.2 && <0.3,base >=4.9 && <4.10,base64-bytestring >=1.0 && <1.1,bytestring >=0.10 && <0.11,containers >=0.5 && <0.6,deepseq >=1.4 && <1.5,definitive-base >=2.6 && <2.7,definitive-filesystem >=2.1 && <2.2,definitive-network >=1.4 && <1.5,definitive-parser >=2.5 && <2.6,directory >=1.3 && <1.4,entropy >=0.3 && <0.4,fsnotify,network >=2.6 && <2.7,process >=1.4 && <1.5,zlib >=0.6 && <0.7
if flag(paranoid)
ghc-options: -Wall -Werror
hs-source-dirs: src
c-sources: sha256.c
default-language: Haskell2010
......@@ -26,7 +26,7 @@ import IO.Filesystem ((</>),dropFileName)
import IO.Network.Socket (PortNumber,connect,getAddrInfo)
import System.Directory (createDirectoryIfMissing)
import System.Environment (lookupEnv)
import System.INotify
import qualified System.FSNotify as FSNotify
import System.IO (openFile,IOMode(AppendMode),hSetBuffering,BufferMode(LineBuffering))
import qualified Data.ByteString.Base64 as Base64
import Codec.Compression.Zlib (compress,decompress)
......@@ -312,11 +312,11 @@ liftIOLog :: MonadIO m => IO () -> m ()
liftIOLog = liftIO . trylogLevel Quiet unit
-- | A global INotify instance
inotify :: INotify
inotify = initINotify^.thunk
inotify :: FSNotify.WatchManager
inotify = FSNotify.startManager^.thunk
-- | Sets a watch on the given file, on the usual signals
watchFile :: FilePath -> IO () -> IO WatchDescriptor
watchFile s f = addWatch inotify [Modify,Create,Delete,Move,MoveIn,MoveOut,MoveSelf] s (\_ -> f)
watchFile :: FilePath -> IO () -> IO (IO ())
watchFile s f = FSNotify.watchTree inotify s (const True) (\_ -> f)
-- | A utility function that opens a client socket to the given server and port
connectTo :: String -> PortNumber -> IO Handle
......
{-# LANGUAGE TypeFamilies, StandaloneDeriving #-}
module Curly.Core.Library(
-- * Modules
-- ** Chunked data and Future Extensions
Chunked(..),Extension,FutureExtensionTail,ExtensionDefault(..),FutureExtension,
-- ** Nodes
ModDir(..),i'ModDir,Module,Mountain,Context,context,localContext,
atM,atMs,fromPList,
......@@ -11,7 +13,7 @@ module Curly.Core.Library(
GlobalID(..),isLibData,
Metadata(..),Library,metadata,imports,exports,symbols,implicits,
addImport,addExport,setExports,defSymbol,libSymbol,
exprIn,optExprIn,builtinLibs,
exprIn,optExprIn,builtinsLib,
-- ** Documentation
LeafExpr,DocNode(..),Documentation,docNodeAttrs,docNodeSubs,descSymbol,docAtom,docLine,mkDoc,
-- * Files
......@@ -37,16 +39,34 @@ import Control.Concurrent.MVar
curlyLibVersion :: Int
curlyLibVersion = 11
binaryEOI :: (MonadParser s m p, Monoid s, Eq s) => p ()
binaryEOI = guard . (==zero) =<< remaining
newtype Chunked a = Chunked { getChunked :: a }
instance Serializable a => Serializable (Chunked a) where
encode (Chunked a) = encode (serialize a)
instance Format a => Format (Chunked a) where
datum = datum <&> \x -> maybe (error "Invalid chunked value") Chunked (matches Just (datum <* (guard . (==zero) =<< remaining)) x)
datum = datum <&> \x -> maybe (error "No parse for chunked data") Chunked (matches Just (datum <* binaryEOI) x)
data FutureExtensionTail = FutureExtensionTail
instance Serializable FutureExtensionTail where
encode = zero
instance Format FutureExtensionTail where
datum = runStreamState (put zero) >> return FutureExtensionTail
type FutureExtension = Extension FutureExtensionTail
class ExtensionDefault t where
extensionDefault :: t
instance ExtensionDefault FutureExtensionTail where extensionDefault = FutureExtensionTail
instance ExtensionDefault (Maybe a) where extensionDefault = Nothing
instance (ExtensionDefault a, ExtensionDefault b) => ExtensionDefault (a,b) where
extensionDefault = (extensionDefault,extensionDefault)
instance ExtensionDefault a => ExtensionDefault (Extension a) where
extensionDefault = Extension (Chunked extensionDefault)
newtype Extension a = Extension (Chunked a)
deriving Serializable
instance Format a => Format (Extension a) where
datum = coerceDatum Extension
instance (ExtensionDefault a,Format a) => Format (Extension a) where
datum = datum <&> \x -> maybe (error "No parse for extension") (Extension . Chunked) (matches Just (datum <+? fill extensionDefault binaryEOI) x)
newtype ModDir s a = ModDir [(s,a)]
deriving (Semigroup,Monoid,Show)
......@@ -110,7 +130,7 @@ data ModLeaf s a = ModLeaf {
_leafType :: Type s,
_leafIsFamily :: Bool,
_leafStrictness :: Strictness s,
_leafExtension :: Extension (),
_leafExtension :: Extension (Maybe Documentation, FutureExtension),
_leafVal :: a
}
deriving Generic
......@@ -166,7 +186,7 @@ data Library = Library {
_externalSyms :: Map String GlobalID,
_implicits :: InstanceMap GlobalID (Maybe LibraryID,LeafExpr GlobalID),
_exports :: Context,
_libExtension :: Extension ()
_libExtension :: FutureExtension
}
metadata :: Lens' Library (Metadata)
......@@ -185,7 +205,7 @@ exports = lens _exports (\x y -> x { _exports = y })
instance Semigroup Library where
Library syn i s es is e ext + Library _ i' s' es' is' e' _ = Library syn (i+i') (s+s') (es+es') (is+is') (e+e') ext
instance Monoid Library where
zero = Library (Metadata zero) zero zero zero zero zero (Extension (Chunked ()))
zero = Library (Metadata zero) zero zero zero zero zero (Extension (Chunked FutureExtensionTail))
cylMagic :: String
cylMagic = "#!/lib/cyl!# "
newtype ParEncode t = ParEncode t
......@@ -219,7 +239,7 @@ type LibRep s = (Metadata,Module s
,Map String s
,InstanceMap s (ExprRep s)
,Set LibraryID
,Module s,Extension ())
,Module s,FutureExtension)
scoped :: Iso' Library (LibRep GlobalID)
scoped = iso f g
where f (Library syn i s es is e ext) = (syn,map fst i,map2 toExpr s,es,map2 toExpr (filterInsts is),instDeps,map fst e,ext)
......@@ -322,8 +342,8 @@ localContext = context ?mountain
undefSym :: NameExpr GlobalID
undefSym = mkSymbol (pureIdent "undefined",Pure (Builtin (builtinType B_Undefined) B_Undefined))
undefLeaf :: String -> LeafExpr GlobalID
undefLeaf msg = ModLeaf (nodoc msg) NoRange zero False noStrictness (Extension (Chunked ext)) undefSym
where ext = ()
undefLeaf msg = ModLeaf (nodoc msg) NoRange zero False noStrictness extensionDefault undefSym
undefSymLeaf :: String -> Maybe LibraryID -> LeafExpr GlobalID
undefSymLeaf s ml = undefLeaf (format "Undocumented symbol %s%s" s (case ml of Just l -> format " in %s" (show l)
Nothing -> ""))
......@@ -367,10 +387,11 @@ libSymbol :: Library -> GlobalID -> Maybe (LeafExpr GlobalID)
libSymbol l (GlobalID i Nothing) = l^.symbols.at i
libSymbol _ (GlobalID _ (Just (i,lid))) = findLib lid >>= \l -> l^.flLibrary.symbols.at i
builtinLibs :: [FileLibrary]
builtinLibs = map (\l -> rawLibrary False l (serialize l) Nothing)
[blib_4,blib_3]
builtinsLib :: FileLibrary
builtinsLib = rawLibrary False blib (serialize blib) Nothing
where
blib = blib_5
blib_5 = blib_4 & setMeta ["name"] "curly-builtins"
blib_4 = blib_3 & setMeta ["author","email"] "marc.coiffier@curly-lang.org"
blib_3 = blib_2 & set (sym ["string"] "showInt".leafDoc) (mkDoc "leafDoc" showIntDoc)
where showIntDoc = "{section {title Show Number} {p Produces a string representation of its argument}}"
......@@ -568,7 +589,7 @@ readCachedLibrary l = do
return (registerLib $ FileLibrary f b l False Nothing)
registerBuiltinsLib :: ()
registerBuiltinsLib = by thunk $ void (yb thunk (head builtinLibs))
registerBuiltinsLib = by thunk $ void (yb thunk builtinsLib)
findLib :: LibraryID -> Maybe FileLibrary
findLib l = registerBuiltinsLib`seq`by thunk $ do
......
......@@ -15,11 +15,21 @@ description:
This library aims to be very simple and pleasant to use, with the downside of
deciding some of the implementation details, like timeout intervals and
k-bucket size, for the user.
.
Maintainer note: this package is a fork of the original kademlia
package, made to accomodate the need for record validation before
insertion into the hash table. This is made evident by the
addition of the `i -> a -> Bool` argument to the `create`
function, that should return True when the key `i` validates the
content `a`. In turn, this can be useful for implementing
identity- or content-addressed hash tables that are a little more
resistant to adverse tampering.
license: BSD3
license-file: LICENSE
author: fro_ozen <fro_ozen@gmx.de>
maintainer: fro_ozen <fro_ozen@gmx.de>
maintainer: Marc Coiffier <marc.coiffier@univ-grenoble-alpes.fr>
category: Network
build-type: Simple
......
......@@ -3,18 +3,22 @@
name: curly-system
version: 0.3.2
-- synopsis:
synopsis: System-specific code generation libraries for the Curly compiler
-- description:
license: MIT
license-file: LICENSE
author: Marc Coiffier
maintainer: marc.coiffier@univ-grenoble-alpes.fr
-- copyright:
-- category:
category: Compilers
build-type: Simple
extra-source-files: ChangeLog.md
cabal-version: >=1.10
flag paranoid
default: False
manual: True
library
exposed-modules: Curly.System, Curly.System.HTML, Curly.System.Base, Curly.System.JavaScript, Curly.System.X86.Common, Curly.System.X86.Linux, Curly.System.ARM.Common, Curly.System.ARM.Linux, Curly.System.Format.ELF, Curly.System.Format.JVM.Class
-- other-modules:
......@@ -31,5 +35,6 @@ library
other-extensions: UndecidableInstances, RecursiveDo, ScopedTypeVariables, NoMonomorphismRestriction, PatternSynonyms, CPP, TypeFamilies, StandaloneDeriving
build-depends: base >=4.9 && <4.10,curly-core >=0.7 && <0.8,definitive-base >=2.6 && <2.7,definitive-filesystem >=2.1 && <2.2,definitive-parser >=2.5 && <2.6
hs-source-dirs: src
ghc-options: -Werror
if flag(paranoid)
ghc-options: -Werror
default-language: Haskell2010
......@@ -36,8 +36,7 @@ knownSystems = fromAList $ ("host",hostSystem):[(_sysName s,s) | s <- [X86_Linux
hostSystem :: System
hostSystem = X86_Linux.system64
mkRunExpr e = mkApply e (mkSymbol (Builtin zero B_Unit))
mkRunExpr e = mkApply e (mkAbstract (pureIdent "x") (mkSymbol (Argument 0)))
specializeStandalone :: System -> LeafExpr GlobalID -> Bytes
specializeStandalone sys e = let ?sys = sys in
......@@ -58,7 +57,7 @@ jd_sections :: Lens' (JITData s) (Map Section [ForeignPtr ()])
jd_sections = lens _jd_sections (\x y -> x { _jd_sections = y })
data JITContext s = JITContext (IORef (JITData s))
type RunJITExpr = IO ()
type RunJITExpr = IO CInt
runJIT :: JITContext s -> ASMT s Id BinAddress -> IO RunJITExpr
runJIT (JITContext cxt) asm = let allocSections = [InitSection,TextSection,DataSection] in mdo
rt <- runAtomic cxt $ do
......@@ -71,11 +70,12 @@ runJIT (JITContext cxt) asm = let allocSections = [InitSection,TextSection,DataS
liftA2 (,) (getCounter <* reserve thunkSize 0) (getCounter <* reserve thunkSize 0)
start <- inSection TextSection m
inSection InitSection $ do
pushing [destReg,thisReg,tmpReg,poolReg] $ do
pushing (select (/=cret) [destReg,thisReg,tmpReg,poolReg]) $ do
destReg <-- dest
thisReg <-- this
poolReg <-- (0 :: Int)
call start
cret <-- destReg!ValueOffset
ret
jd_runtime <~ \rt -> let Id ~(_,rt',_) = runASMT rt (withJITRuntime asm)
in (rt',rt')
......@@ -104,7 +104,7 @@ type Wrapper t = t -> IO (FunPtr t)
class CCallable f where
wrapper :: Wrapper f
foreign import ccall "dynamic" runIOFunPtr :: FunPtr (IO ()) -> IO ()
foreign import ccall "dynamic" runIOFunPtr :: FunPtr RunJITExpr -> RunJITExpr
hsAddr :: CCallable a => a -> BinAddress
hsAddr fun = BA (fromIntegral (ptrToIntPtr (castFunPtrToPtr p)))
......
......@@ -195,6 +195,7 @@ data VonNeumannMachine = VonNeumannMachine {
}
data AssemblyMachine = AssemblyMachine {
_ccall :: CCALL,
_cret :: RegID,
_poolReg :: RegID,
_wordSize :: Int,
_pageSize :: Int
......@@ -476,6 +477,8 @@ ccall2 ml a v1 v2 = ccall ml a [map toValue v1, map toValue v2]
ccall3 :: (?sys :: VonNeumannMachine,MonadASM m s,IsLocus l,IsValue v,IsValue v',IsValue v'') => Maybe l -> BinAddress ->
m v -> m v' -> m v'' -> m ()
ccall3 ml a v1 v2 v3 = ccall ml a [map toValue v1, map toValue v2, map toValue v3]
cret :: (?sys :: VonNeumannMachine) => RegID
cret = _cret assemblyMachine
poolReg :: (?sys :: VonNeumannMachine) => RegID
poolReg = _poolReg assemblyMachine
......
......@@ -365,6 +365,7 @@ x86_machine_common = VonNeumannMachine {
_curlyBuiltin = let ?sys = x86_machine_common in commonBuiltin,
_assemblyMachine = Just AssemblyMachine {
_ccall = x86_ccall,
_cret = reg R_eax,
_poolReg = reg R_ebp_ch,
_wordSize = x86_wordSize,
_pageSize = 4096
......
......@@ -158,6 +158,8 @@ x86_linux_system name = x86_sys name prog x86_machine_linux
prog = Standalone $ \mtext -> x86_common $ do
mute $ rawProgram [InitSection,TextSection,DataSection] $ do
rtSection InitSection .l'2 =- BA pstart
rtSection TextSection .l'2 =~ \(BA x) -> BA (x+0x400000)
rtSection DataSection .l'2 =~ \(BA x) -> (BA (x+0x400000))
start <- mtext
inSection InitSection $ do
poolReg <-- Constant 0
......@@ -169,11 +171,11 @@ x86_linux_system name = x86_sys name prog x86_machine_linux
call start
x86_linux_syscall SC_Exit [pure (Constant 0)]
rt <- get
let BA tstart = rt^.rtSection InitSection .l'2
BA dstart = rt^.rtSection TextSection .l'2
let BA tstart = BA 0x400000 + rt^.rtSection InitSection .l'2
BA dstart = BA 0x400000 + rt^.rtSection TextSection .l'2
ser p = serialize $ Elf ET_Exec (p pstart) [
ElfSection ".init" (ElfProgbits (p pstart) (True,True,True) (rt^.rtSection InitSection .l'1.bData)),
ElfSection ".text" (ElfProgbits (p tstart) (True,True,True) (rt^.rtSection TextSection .l'1.bData)),
ElfSection ".init" (ElfProgbits (p pstart) (True,False,True) (rt^.rtSection InitSection .l'1.bData)),
ElfSection ".text" (ElfProgbits (p tstart) (True,False,True) (rt^.rtSection TextSection .l'1.bData)),
ElfSection ".data" (ElfProgbits (p dstart) (True,True,False) (rt^.rtSection DataSection .l'1.bData)),
ElfSection ".symtab" (ElfSymTab (from ascList $^ map (\((sec,sym),BA addr) -> (secName sec+"."+sym,(secName sec,p addr)))
$ ascList $^ rt^.rtBuiltins))]
......@@ -182,7 +184,7 @@ x86_linux_system name = x86_sys name prog x86_machine_linux
secName DataSection = ".data"
secName (RawSection n) = ".raw."+n
tell $ bytesCode' $ if32 (ser (Linux_X86_ElfN . fromIntegral)) (ser (Linux_X86_64_ElfN . fromIntegral))
pstart = 0x40000000 + fromIntegral (if32 (ehSize linux_x86) (ehSize linux_x64))
pstart = 0x400000 + fromIntegral (if32 (ehSize linux_x86) (ehSize linux_x64))
x86_defBuiltin :: (?x86 :: X86,?sysHooks :: SystemHooks,MonadASM m s) => String -> ((?sys :: VonNeumannMachine) => m ()) -> Maybe (m (BinAddress,Value))
x86_defBuiltin name m = Just $ x86_extended $ (,Constant 0) <$> getOrDefine TextSection name m
......
......@@ -3,17 +3,18 @@
name: curly
version: 0.59.4
-- synopsis:
synopsis: A minimal cross-compiler for the simply-typed lambda-calculus
-- description:
license: MIT
license-file: LICENSE
author: Marc Coiffier
maintainer: marc.coiffier@univ-grenoble-alpes.fr
-- copyright:
-- category:
category: Compilers
build-type: Simple
extra-source-files: ChangeLog.md
cabal-version: >=1.10
homepage: http://www.curly-lang.org/
data-dir: data
data-files:
......@@ -55,7 +56,7 @@ library
RankNTypes
TypeFamilies
LambdaCase
other-extensions: CPP, ExistentialQuantification, ViewPatterns, TypeFamilies, ScopedTypeVariables, RecursiveDo, DeriveGeneric, NoMonomorphismRestriction
other-extensions: CPP, ExistentialQuantification, ViewPatterns, TypeFamilies, ScopedTypeVariables, RecursiveDo, DeriveGeneric, NoMonomorphismRestriction, QuasiQuotes, TemplateHaskell
build-depends: base >=4.9 && <4.10,curly-core >=0.7 && <0.8,curly-system >=0.3 && <0.4,deepseq >=1.4 && <1.5,definitive-base >=2.6 && <2.7,definitive-filesystem >=2.1 && <2.2,definitive-network >=1.4 && <1.5,definitive-parser >=2.5 && <2.6,directory >=1.3 && <1.4,filepath >=1.4 && <1.5,process >=1.4 && <1.5,terminal-size >=0.3 && <0.4,unix >=2.7 && <2.8, template-haskell
hs-source-dirs: src
......
#!/bin/bash
declare -gA BASHCOMPS
declare -gA COMP_DESCRIPTIONS
declare -gA INTERPRETER_COMPS
if [ -z "$INCLUDED_BASHCOMPS" ]; then
INCLUDED_BASHCOMPS=true
declare -gix CI_PREFIX=0 CI_REST=1 CI_POP=2
function C.testBashCorrectness() {
# Some versions of Bash give incorrect results when splicing arrays
# that contain empty strings, so we need to check if we are running
# in a compatible environment
local -a foo=( '' '' )
local -a bar=( "${foo[@]:1}" )
(( ${#bar[@]} == 1 ))
}
if C.testBashCorrectness; then
function C.popState() { COMPSTATE=( "$@" "${COMPSTATE[@]:$CI_POP}" ); }
function C.adjustWords() { COMP_WORDS=( "${COMP_WORDS[@]:1:$COMP_CWORD}" ); }
else
function C.popState() {
if [ "${COMPSTATE[CI_POP]}" != '' ]; then
COMPSTATE=( "$@" "${COMPSTATE[@]:$CI_POP}" )
else
if (( ${#COMPSTATE[@]} == CI_POP+1 )); then
COMPSTATE=( "$@" "${COMPSTATE[CI_POP]}" )
else
COMPSTATE=( "$@" "${COMPSTATE[@]:$CI_POP}" )
fi
fi
}
function C.adjustWords() {
if (( ${#COMP_WORDS[@]} == 2 )) && [ "${COMP_WORDS[1]}" == '' ]; then
COMP_WORDS=( "" )
else
COMP_WORDS=( "${COMP_WORDS[@]:1:$COMP_CWORD}" )
fi
}
fi
function C.defcomp() {
local comp="$1"
shift
for cmd; do
BASHCOMPS[$cmd]="$comp"
complete -o nospace -F C.complete "$cmd"
done
}
function C.defcomp.default {
local comp="$1"
for cmd; do INTERPRETER_COMPS[.$cmd]="$comp"; done
}
function C.complete() {
COMPREPLY=( )
C.adjustWords
local -a COMPSTATE=( "" )
local COMP_PROGRAM="$1"
local i=0 j=1
for ((i=0;i<${#COMP_WORDS[@]};i++)); do
case "${COMP_WORDS[i]}" in
[$COMP_WORDBREAKS]) COMPSTATE[j-1]+="${COMP_WORDS[i]}${COMP_WORDS[i+1]}"; ((i++));;
*) COMPSTATE[j]="${COMP_WORDS[i]}"; ((j++));;
esac
done
local C_RET=1 prefix=":${COMPSTATE[j-1]}" prefsuf
prefix="${prefix%[$COMP_WORDBREAKS]*}"
prefix="${prefix:1}"
prefsuf="${COMPSTATE[j-1]#$prefix}"
eval "${BASHCOMPS[${COMP_PROGRAM##*/}]:-:}" && {
IFSBAK="$IFS" IFS=$'\n' COMPREPLY=( $(printf '%s\n' "${COMPREPLY[@]}" | sort -u) ) IFS="$IFSBAK"
if [ "${#COMPREPLY[@]}" -gt 1 ]; then
local -a heads=( ) tails=( )
local head tail hsz=0 tsz=0
for comp in "${COMPREPLY[@]}"; do
head="${comp% -- *}" ; tail="${comp##*--}"
if (( ${#head} > hsz )); then hsz=${#head}; fi
if (( ${#tail} > tsz )); then tsz=${#tail}; fi
done
local spaces="$(printf '%150s' '')" newcomp
local -a newreply=( )
for comp in "${COMPREPLY[@]}"; do
head="${comp% -- *}$spaces" ; tail="${comp##* -- }"
tail="${tail:+ -- ${tail:0:$tsz}$spaces}"
newcomp="${head:0:$hsz}${tail:0:$((tsz+4))}"
newreply+=( "$newcomp" )
done
COMPREPLY=( "${newreply[@]}" )
else
COMPREPLY=( "${COMPREPLY[@]% -- *}" )
fi
if [ -n "$prefix" ]; then
COMPREPLY=( "${COMPREPLY[@]#$prefix${prefsuf:0:1}}" )
fi
}
}
function C.leaf() { (( ${#COMPSTATE[@]} < 2 )); }
function C.argument() {
local argtype="$1" arg prefix
shift
: ${COMP_SUFFIX:= }
if C.leaf; then
return 1
else
prefix="${COMPSTATE[CI_PREFIX]}"
case "$argtype:${COMPSTATE[CI_REST]}" in
word:*)
if [ "$COMP_SUFFIX" != " " ]; then
local whole="${COMPSTATE[CI_REST]}"
arg="${whole%%${COMP_SUFFIX:0:1}*}"
if [ "$whole" = "$arg" ] ; then
C.popState ""
else
COMPSTATE[CI_PREFIX]+="$arg$COMP_SUFFIX"
COMPSTATE[CI_REST]="${whole#$arg${COMP_SUFFIX:0:$((${#whole} - ${#arg}))}}"
fi
else
arg="${COMPSTATE[CI_REST]}"
C.popState ""
fi
;;
opt:--*=*)
arg="${COMPSTATE[CI_REST]%%=*}"
C.popState "$arg=" "${COMPSTATE[CI_REST]#*=}"
;;
flag:--*|opt:|flag:|opt:-|flag:-|opt:--*)
arg="${COMPSTATE[CI_REST]}"
C.popState ""
;;
opt:-?*)
arg="${COMPSTATE[CI_REST]:0:2}"
COMPSTATE[CI_PREFIX]="${COMPSTATE[CI_PREFIX]:--}${arg#-}"
COMPSTATE[CI_REST]="${COMPSTATE[CI_REST]:2}"
if [ -n "${COMPSTATE[CI_REST]}" ]; then :; else
if (( ${#COMPSTATE[@]} > 2 )); then
C.popState ""
fi
fi
;;
flag:-?*)
arg="${COMPSTATE[CI_REST]:0:2}"
COMPSTATE[CI_PREFIX]="${COMPSTATE[CI_PREFIX]:--}${arg#-}"
COMPSTATE[CI_REST]="-${COMPSTATE[CI_REST]:2}"
if [ "${COMPSTATE[CI_REST]}" == - ] && (( ${#COMPSTATE[@]} > 2 )); then
C.popState ""
fi
;;
*) return 1;;
esac
local -a COMPLETIONS=( ) SUGGESTIONS=( )
"$1" "$arg" "${@:2}" && {
local -a descriptions
case "$argtype" in
flag|opt)
case "$prefix" in
-[^-]*)
local -a newc=( )
for c in "${COMPLETIONS[@]}"; do
if [[ "$c" != --* ]]; then newc+=( "$c" ); fi
done
COMPLETIONS=( "${newc[@]}" )
;;
esac
descriptions=( "${COMPLETIONS[@]##* -- }" )
COMPLETIONS=( "${COMPLETIONS[@]% -- *}" )
COMPLETIONS=( "${COMPLETIONS[@]/#-/${prefix:--}}" )
if [[ "$COMPLETIONS" == --* ]]; then
if [ "$argtype" == opt ]; then
COMPLETIONS=( "${COMPLETIONS[@]/%/=}" )
else
COMPLETIONS=( "${COMPLETIONS[@]/%/ }" )
fi
fi
;;
*)
descriptions=( "${COMPLETIONS[@]##* -- }" )
COMPLETIONS=( "${COMPLETIONS[@]% -- *}" )
COMPLETIONS=( "${COMPLETIONS[@]/%/$COMP_SUFFIX}" )
COMPLETIONS=( "${COMPLETIONS[@]/#/$prefix}" )
;;
esac
for ((i=0;i<${#COMPLETIONS[@]};i++)); do
COMPLETIONS[i]+=" -- ${descriptions[i]}"
done
COMPREPLY+=( "${COMPLETIONS[@]}" )
}
fi
}
function C.suffixed() { local COMP_SUFFIX="$1"; "${@:2}"; }
function C.describing() { local COMP_DESCRIPTION="$1"; "${@:2}"; }
function C.normal() { local COMP_SUFFIX= COMP_DESCRIPTION=; "$@"; }
function C.save() {
local -a OLD_COMPSTATE
OLD_COMPSTATE=( "${COMPSTATE[@]}" )
"$@" || {
COMPSTATE=( "${OLD_COMPSTATE[@]}" )
return 1
}
}
function C.alt() {
local -a OLD_COMPSTATE
local ret
OLD_COMPSTATE=( "${COMPSTATE[@]}" )
"$@"