Skip to content

Commit babf406

Browse files
committed
Implement AbstractFilePath
1 parent 4638d2a commit babf406

36 files changed

+5254
-2446
lines changed

.github/workflows/test.yaml

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,43 +14,45 @@ jobs:
1414
fail-fast: false
1515
matrix:
1616
os: [ubuntu-latest, macOS-latest, windows-latest]
17-
ghc: ['8.0.2', '8.2.2', '8.4.4', '8.6.5', '8.8.4', '8.10.7', '9.0.2', '9.2.1']
18-
cabal: ['3.6.2.0']
17+
ghc: ['8.0', '8.2', '8.4', '8.6', '8.8', '8.10', '9.0', '9.2']
18+
cabal: ['latest']
1919
include:
20-
- os: ubuntu-latest
21-
ghc: 'HEAD'
22-
experimental: true
2320
- os: ubuntu-latest
2421
ghc: 'recommended'
2522
experimental: true
2623
- os: ubuntu-latest
2724
ghc: 'latest'
2825
experimental: true
26+
- os: windows-latest
27+
ghc: '9.2.1'
28+
experimental: true
2929
exclude:
3030
- os: macOS-latest
31-
ghc: '8.0.2'
31+
ghc: '8.0'
3232
- os: macOS-latest
33-
ghc: '8.2.2'
33+
ghc: '8.2'
3434
- os: macOS-latest
35-
ghc: '8.4.4'
35+
ghc: '8.4'
3636
- os: macOS-latest
37-
ghc: '8.6.5'
37+
ghc: '8.6'
3838
- os: macOS-latest
39-
ghc: '8.8.4'
39+
ghc: '8.8'
4040
- os: macOS-latest
41-
ghc: '9.0.2'
41+
ghc: '9.0'
42+
- os: windows-latest
43+
ghc: '8.0'
4244
- os: windows-latest
43-
ghc: '8.0.2'
45+
ghc: '8.2'
4446
- os: windows-latest
45-
ghc: '8.2.2'
47+
ghc: '8.4'
4648
- os: windows-latest
47-
ghc: '8.4.4'
49+
ghc: '8.6'
4850
- os: windows-latest
49-
ghc: '8.6.5'
51+
ghc: '8.8'
5052
- os: windows-latest
51-
ghc: '8.8.4'
53+
ghc: '9.0'
5254
- os: windows-latest
53-
ghc: '9.0.2'
55+
ghc: '9.2'
5456

5557
steps:
5658
- uses: actions/checkout@v2
@@ -59,22 +61,20 @@ jobs:
5961
run: |
6062
set -eux
6163
if [ "${{ matrix.ghc }}" == 'HEAD' ] ; then
62-
ghcup install ghc -u 'https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-deb10-linux.tar.xz?job=validate-x86_64-linux-deb10-hadrian' head
63-
ghcup set ghc head
64+
ghcup install ghc -u 'https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-deb10-linux.tar.xz?job=validate-x86_64-linux-deb10-unreg-hadrian' --set head
6465
else
65-
ghcup install ghc ${{ matrix.ghc }}
66-
ghcup set ghc ${{ matrix.ghc }}
66+
ghcup install ghc --set ${{ matrix.ghc }}
6767
fi
6868
ghcup install cabal ${{ matrix.cabal }}
6969
shell: bash
7070

7171
- name: Build
7272
run: |
7373
set -eux
74-
[ "${{ matrix.ghc }}" == 'HEAD' ] ||
75-
[ "${{ matrix.ghc }}" == 'recommended' ] ||
76-
[ "${{ matrix.ghc }}" == 'latest' ] ||
77-
[ "$(ghc --numeric-version)" = "${{ matrix.ghc }}" ]
74+
[[ "${{ matrix.ghc }}" == 'HEAD' ]] ||
75+
[[ "${{ matrix.ghc }}" == 'recommended' ]] ||
76+
[[ "${{ matrix.ghc }}" == 'latest' ]] ||
77+
[[ "$(ghc --numeric-version)" =~ "${{ matrix.ghc }}" ]]
7878
cabal update
7979
cabal build --enable-tests --enable-benchmarks
8080
cabal test
@@ -102,33 +102,83 @@ jobs:
102102
steps:
103103
- uses: actions/checkout@v2
104104
- uses: uraimo/run-on-arch-action@v2.1.1
105-
timeout-minutes: 60
105+
timeout-minutes: 180
106106
with:
107107
arch: ${{ matrix.arch }}
108108
distro: ubuntu20.04
109109
githubToken: ${{ github.token }}
110110
install: |
111111
apt-get update -y
112-
apt-get install -y ghc libghc-quickcheck2-dev cpphs git make
112+
apt-get install -y ghc libghc-quickcheck2-dev libghc-tasty-dev libghc-tasty-quickcheck-dev cpphs git make curl
113113
run: |
114+
curl -O https://hackage.haskell.org/package/bytestring-0.11.3.0/bytestring-0.11.3.0.tar.gz
115+
tar xf bytestring-0.11.3.0.tar.gz
116+
rm bytestring-0.11.3.0.tar.gz
117+
cd bytestring-0.11.3.0
118+
find . -type f -not -path './Data/ByteString/Short.hs' -a -not -path './Data/ByteString/Internal.hs' -a -not -path './Data/ByteString/Short/Internal.hs' -a -not -path './cbits/*' -a -not -path './include/*' -delete
119+
cd cbits/
120+
gcc -c -I../include -I/usr/lib/ghc/include/ -std=c11 -fPIC -DNDEBUG=1 *.c
121+
gcc -shared -o libshortbytestring.so *.o
122+
mv libshortbytestring.so /usr/lib/
123+
cd ../../
114124
ghc --version
115-
ghc --make -o Main tests/Test.hs -itests/ +RTS -s
125+
runhaskell --ghc-arg=-DGHC_MAKE Generate.hs
126+
ghc --make -o Main tests/Test.hs -DGHC_MAKE -itests/ -ibytestring-0.11.3.0/ -L./bytestring-0.11.3.0/cbits/ -lshortbytestring +RTS -s
127+
./Main +RTS -s
128+
ghc --make -o Main tests/Main.hs -DGHC_MAKE -itests/ -ibytestring-0.11.3.0/ -L./bytestring-0.11.3.0/cbits/ -lshortbytestring +RTS -s
116129
./Main +RTS -s
117130
118131
emulated-i386:
119132
runs-on: ubuntu-latest
120133
container:
121-
image: i386/ubuntu:bionic
134+
image: i386/debian:sid
122135
steps:
123136
- name: install
124137
run: |
125138
apt-get update -y
126-
apt-get install -y ghc libghc-quickcheck2-dev cpphs git make
139+
apt-get install -y ghc libghc-quickcheck2-dev libghc-tasty-dev libghc-tasty-quickcheck-dev cpphs git make curl libghc-exceptions-dev
127140
shell: bash
128141
- uses: actions/checkout@v1
129142
- name: test
130143
run: |
144+
curl -O https://hackage.haskell.org/package/bytestring-0.11.3.0/bytestring-0.11.3.0.tar.gz
145+
tar xf bytestring-0.11.3.0.tar.gz
146+
rm bytestring-0.11.3.0.tar.gz
147+
cd bytestring-0.11.3.0
148+
find . -type f -not -path './Data/ByteString/Short.hs' -a -not -path './Data/ByteString/Internal.hs' -a -not -path './Data/ByteString/Short/Internal.hs' -a -not -path './cbits/*' -a -not -path './include/*' -delete
149+
cd cbits/
150+
gcc -c -I../include -I/usr/lib/ghc/include/ -std=c11 -fPIC -DNDEBUG=1 *.c
151+
gcc -shared -o libshortbytestring.so *.o
152+
mv libshortbytestring.so /usr/lib/
153+
cd ../../
131154
ghc --version
132-
ghc --make -o Main tests/Test.hs -itests/ +RTS -s
155+
runhaskell --ghc-arg=-DGHC_MAKE Generate.hs
156+
ghc --make -o Main tests/Test.hs -DGHC_MAKE -itests/ -ibytestring-0.11.3.0/ -L./bytestring-0.11.3.0/cbits/ -lshortbytestring +RTS -s
157+
./Main +RTS -s
158+
ghc --make -o Main tests/Main.hs -DGHC_MAKE -itests/ -ibytestring-0.11.3.0/ -L./bytestring-0.11.3.0/cbits/ -lshortbytestring +RTS -s
133159
./Main +RTS -s
134160
shell: bash
161+
162+
bounds-checking:
163+
needs: build
164+
runs-on: ubuntu-latest
165+
steps:
166+
- uses: actions/checkout@v2
167+
- name: Test
168+
run: |
169+
ghcup install ghc --set 9.2.2
170+
ghcup install cabal latest
171+
cabal update
172+
cabal run -w ghc-9.2.2 --ghc-options='-fcheck-prim-bounds -fno-ignore-asserts' bytestring-tests
173+
174+
sdist:
175+
runs-on: ubuntu-latest
176+
steps:
177+
- uses: actions/checkout@v2
178+
- name: Test
179+
run: |
180+
cabal update
181+
cabal sdist
182+
tar xf dist-newstyle/sdist/filepath-*.tar.gz
183+
cd filepath-*
184+
cabal build

Generate.hs

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
{-# LANGUAGE RecordWildCards, ViewPatterns #-}
1+
{-# LANGUAGE CPP, RecordWildCards, ViewPatterns #-}
22

33
module Generate(main) where
44

55
import Control.Exception
66
import Control.Monad
7+
import Data.Semigroup
78
import Data.Char
89
import Data.List
910
import System.Directory
@@ -16,19 +17,36 @@ main = do
1617
let tests = map renderTest $ concatMap parseTest $ lines src
1718
writeFileBinaryChanged "tests/TestGen.hs" $ unlines $
1819
["-- GENERATED CODE: See ../Generate.hs"
20+
#ifndef GHC_MAKE
21+
, "{-# LANGUAGE OverloadedStrings #-}"
22+
, "{-# LANGUAGE ViewPatterns #-}"
23+
#endif
1924
,"module TestGen(tests) where"
2025
,"import TestUtil"
26+
,"import Prelude as P"
27+
,"import Data.Semigroup"
28+
,"import qualified Data.Char as C"
29+
,"import qualified Data.ByteString.Short as SBS"
30+
,"import qualified System.AbstractFilePath.Data.ByteString.Short.Word16 as SBS16"
2131
,"import qualified System.FilePath.Windows as W"
2232
,"import qualified System.FilePath.Posix as P"
23-
,"{-# ANN module \"HLint: ignore\" #-}"
33+
#ifdef GHC_MAKE
34+
,"import qualified System.AbstractFilePath.Windows.Internal as AFP_W"
35+
,"import qualified System.AbstractFilePath.Posix.Internal as AFP_P"
36+
#else
37+
,"import System.AbstractFilePath.Types"
38+
,"import qualified System.AbstractFilePath.Windows as AFP_W"
39+
,"import qualified System.AbstractFilePath.Posix as AFP_P"
40+
#endif
41+
, "import System.AbstractFilePath.Data.ByteString.Short.Encode"
2442
,"tests :: [(String, Property)]"
2543
,"tests ="] ++
2644
[" " ++ c ++ "(" ++ show t1 ++ ", " ++ t2 ++ ")" | (c,(t1,t2)) <- zip ("[":repeat ",") tests] ++
2745
[" ]"]
2846

2947

3048

31-
data PW = P | W deriving Show -- Posix or Windows
49+
data PW = P | W | AFP_P | AFP_W deriving Show -- Posix or Windows
3250
data Test = Test
3351
{testPlatform :: PW
3452
,testVars :: [(String,String)] -- generator constructor, variable
@@ -39,19 +57,22 @@ data Test = Test
3957
parseTest :: String -> [Test]
4058
parseTest (stripPrefix "-- > " -> Just x) = platform $ toLexemes x
4159
where
42-
platform ("Windows":":":x) = [valid W x]
43-
platform ("Posix" :":":x) = [valid P x]
44-
platform x = [valid P x, valid W x]
60+
platform ("Windows":":":x) = [valid W x, valid AFP_W x]
61+
platform ("Posix" :":":x) = [valid P x, valid AFP_P x]
62+
platform x = [valid P x, valid W x, valid AFP_P x, valid AFP_W x]
4563

4664
valid p ("Valid":x) = free p a $ drop 1 b
4765
where (a,b) = break (== "=>") x
4866
valid p x = free p [] x
4967

5068
free p val x = Test p [(ctor v, v) | v <- vars] x
5169
where vars = nub $ sort [v | v@[c] <- x, isAlpha c]
52-
ctor v | v < "x" = ""
70+
ctor v | v < "x" = ""
5371
| v `elem` val = "QFilePathValid" ++ show p
54-
| otherwise = "QFilePath"
72+
| otherwise = case p of
73+
AFP_P -> if v == "z" then "QFilePathsAFP_P" else "QFilePathAFP_P"
74+
AFP_W -> if v == "z" then "QFilePathsAFP_W" else "QFilePathAFP_W"
75+
_ -> if v == "z" then "" else "QFilePath"
5576
parseTest _ = []
5677

5778

@@ -80,14 +101,67 @@ renderTest Test{..} = (body, code)
80101
body = fromLexemes $ map (qualify testPlatform) testBody
81102

82103

104+
83105
qualify :: PW -> String -> String
84106
qualify pw str
85-
| str `elem` fpops || (all isAlpha str && length str > 1 && str `notElem` prelude) = show pw ++ "." ++ str
86-
| otherwise = str
107+
| str `elem` fpops || (all isAlpha str && length str > 1 && str `notElem` prelude)
108+
= if str `elem` bs then qualifyBS str else show pw ++ "." ++ str
109+
| otherwise = encode str
87110
where
88-
prelude = ["elem","uncurry","snd","fst","not","null","if","then","else"
89-
,"True","False","Just","Nothing","fromJust","concat","isPrefixOf","isSuffixOf","any","foldr"]
111+
bs = ["null", "concat", "isPrefixOf", "isSuffixOf", "any"]
112+
prelude = ["elem","uncurry","snd","fst","not","if","then","else"
113+
,"True","False","Just","Nothing","fromJust","foldr"]
90114
fpops = ["</>","<.>","-<.>"]
115+
#ifdef GHC_MAKE
116+
encode v
117+
| isString' v = case pw of
118+
AFP_P -> "(encodeUtf8 " <> v <> ")"
119+
AFP_W -> "(encodeUtf16LE " <> v <> ")"
120+
_ -> v
121+
| isChar' v = case pw of
122+
AFP_P -> "(fromIntegral . C.ord $ " <> v <> ")"
123+
AFP_W -> "(fromIntegral . C.ord $ " <> v <> ")"
124+
_ -> v
125+
| otherwise = v
126+
isString' xs@('"':_:_) = last xs == '"'
127+
isString' _ = False
128+
isChar' xs@('\'':_:_) = last xs == '\''
129+
isChar' _ = False
130+
qualifyBS v = case pw of
131+
AFP_P -> "SBS." <> v
132+
AFP_W -> "SBS16." <> v
133+
_ -> v
134+
#else
135+
encode v
136+
| isString' v = case pw of
137+
AFP_P -> "(" <> v <> ")"
138+
AFP_W -> "(" <> v <> ")"
139+
_ -> v
140+
| isChar' v = case pw of
141+
AFP_P -> "(PW . fromIntegral . C.ord $ " <> v <> ")"
142+
AFP_W -> "(WW . fromIntegral . C.ord $ " <> v <> ")"
143+
_ -> v
144+
| otherwise = v
145+
isString' xs@('"':_:_) = last xs == '"'
146+
isString' _ = False
147+
isChar' xs@('\'':_:_) = last xs == '\''
148+
isChar' _ = False
149+
qualifyBS v = case pw of
150+
AFP_P
151+
| v == "concat" -> "(PS . SBS." <> v <> " . fmap unPFP)"
152+
| v == "any" -> "(\\f (unPFP -> x) -> SBS." <> v <> " (f . PW) x)"
153+
| v == "isPrefixOf" -> "(\\(unPFP -> x) (unPFP -> y) -> SBS." <> v <> " x y)"
154+
| v == "isSuffixOf" -> "(\\(unPFP -> x) (unPFP -> y) -> SBS." <> v <> " x y)"
155+
| otherwise -> "(SBS." <> v <> " . unPFP)"
156+
AFP_W
157+
| v == "concat" -> "(WS . SBS16." <> v <> " . fmap unWFP)"
158+
| v == "any" -> "(\\f (unWFP -> x) -> SBS16." <> v <> " (f . WW) x)"
159+
| v == "isPrefixOf" -> "(\\(unWFP -> x) (unWFP -> y) -> SBS16." <> v <> " x y)"
160+
| v == "isSuffixOf" -> "(\\(unWFP -> x) (unWFP -> y) -> SBS16." <> v <> " x y)"
161+
| otherwise -> "(SBS16." <> v <> " . unWFP)"
162+
_ -> v
163+
#endif
164+
91165

92166

93167
---------------------------------------------------------------------

Makefile

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
all: cpp gen
2-
3-
cpp:
4-
cpphs --noline -DIS_WINDOWS=False -DMODULE_NAME=Posix -OSystem/FilePath/Posix.hs System/FilePath/Internal.hs
5-
cpphs --noline -DIS_WINDOWS=True -DMODULE_NAME=Windows -OSystem/FilePath/Windows.hs System/FilePath/Internal.hs
1+
all: gen
62

73
gen:
84
runhaskell Generate.hs
95

10-
.PHONY: all cpp gen
6+
7+
.PHONY: all gen

0 commit comments

Comments
 (0)