Skip to content

Commit ede899b

Browse files
authored
Create Tabular package (#209)
* Create Tabular package * Split up ARRAY-NOTES
1 parent bb53eee commit ede899b

18 files changed

+186
-128
lines changed

.appveyor.yml

+3-4
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,11 @@ install:
2727
- "cabal --version"
2828
- "ghc --version"
2929
- "cabal %CABOPTS% v2-update -vverbose+nowrap"
30-
- "cabal %CABOPTS% v2-install alex --bindir=/hsbin"
31-
- "alex --version"
3230

3331
build: off
3432

3533
test_script:
3634
- "cd %APPVEYOR_BUILD_FOLDER%"
37-
- "make sdist"
38-
- "make sdist-test-only"
35+
- "cabal install happy -f -bootstrap --installdir=./bootstrap-root"
36+
- "cabal build happy -f +bootstrap --with-happy=%APPVEYOR_BUILD_FOLDER%/bootstrap-root/happy"
37+
- "cabal test -f +bootstrap"

.github/workflows/haskell-ci.yml

+10-1
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ jobs:
172172
touch cabal.project
173173
echo "packages: $GITHUB_WORKSPACE/source/." >> cabal.project
174174
echo "packages: $GITHUB_WORKSPACE/source/packages/grammar" >> cabal.project
175+
echo "packages: $GITHUB_WORKSPACE/source/packages/tabular" >> cabal.project
175176
cat cabal.project
176177
- name: sdist
177178
run: |
@@ -183,21 +184,27 @@ jobs:
183184
find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
184185
- name: generate cabal.project
185186
run: |
187+
PKGDIR_happy_tabular="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/happy-tabular-[0-9.]*')"
188+
echo "PKGDIR_happy_tabular=${PKGDIR_happy_tabular}" >> "$GITHUB_ENV"
186189
PKGDIR_happy_grammar="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/happy-grammar-[0-9.]*')"
187190
echo "PKGDIR_happy_grammar=${PKGDIR_happy_grammar}" >> "$GITHUB_ENV"
188191
PKGDIR_happy="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/happy-[0-9.]*')"
189192
echo "PKGDIR_happy=${PKGDIR_happy}" >> "$GITHUB_ENV"
190193
rm -f cabal.project cabal.project.local
191194
touch cabal.project
192195
touch cabal.project.local
196+
echo "packages: ${PKGDIR_happy_tabular}" >> cabal.project
193197
echo "packages: ${PKGDIR_happy_grammar}" >> cabal.project
194198
echo "packages: ${PKGDIR_happy}" >> cabal.project
199+
if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package happy-tabular" >> cabal.project ; fi
200+
if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo " ghc-options: -Werror=missing-methods" >> cabal.project ; fi
195201
if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package happy-grammar" >> cabal.project ; fi
202+
if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo " ghc-options: -Werror=missing-methods" >> cabal.project ; fi
196203
if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package happy" >> cabal.project ; fi
197204
if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo " ghc-options: -Werror=missing-methods" >> cabal.project ; fi
198205
cat >> cabal.project <<EOF
199206
EOF
200-
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(containers|happy|happy-grammar|mtl|transformers)$/; }' >> cabal.project.local
207+
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(containers|happy|happy-tabular|happy-grammar|mtl|transformers)$/; }' >> cabal.project.local
201208
cat cabal.project
202209
cat cabal.project.local
203210
- name: dump install plan
@@ -228,6 +235,8 @@ jobs:
228235
$CABAL v2-test --flags=-bootstrap $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
229236
- name: cabal check
230237
run: |
238+
cd ${PKGDIR_happy_tabular} || false
239+
${CABAL} -vnormal check
231240
cd ${PKGDIR_happy_grammar} || false
232241
${CABAL} -vnormal check
233242
cd ${PKGDIR_happy} || false

cabal.project

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
packages:
22
packages/grammar
3+
packages/tabular
34
./

happy.cabal

+2-8
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ extra-source-files:
112112
examples/ErlParser.ly
113113
examples/SimonsExample.ly
114114
examples/LexerTest.ly
115-
src/ARRAY-NOTES
116115
tests/AttrGrammar001.y
117116
tests/AttrGrammar002.y
118117
tests/Makefile
@@ -160,28 +159,23 @@ executable happy
160159
array,
161160
containers >= 0.4.2,
162161
mtl >= 2.2.1,
163-
happy-grammar == 1.21.0
164-
-- mtl-2.2.1 added Control.Monad.Except
162+
happy-grammar == 1.21.0,
163+
happy-tabular == 1.21.0
165164

166165
default-language: Haskell98
167166
default-extensions: CPP, MagicHash, FlexibleContexts, NamedFieldPuns
168167
ghc-options: -Wall
169168
other-modules:
170169
Paths_happy
171170
AbsSyn
172-
First
173171
GenUtils
174-
Info
175-
LALR
176172
Lexer
177173
Mangler
178174
ParseMonad
179175
ParseMonad.Class
180176
Parser
181177
ProduceCode
182178
ProduceGLRCode
183-
NameSet
184-
Tabular
185179
Target
186180
AttrGrammar
187181
ParamRules

packages/grammar/src/Happy/Grammar.lhs

+32-3
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ The Grammar data type.
1212
> Assoc(..),
1313
>
1414
> errorName, errorTok, startName, dummyName, firstStartTok, dummyTok,
15-
> eofName, epsilonTok
15+
> eofName, epsilonTok,
16+
>
17+
> mapDollarDollar
1618
> ) where
1719

1820
> import Data.Array
19-
21+
> import Data.Char (isAlphaNum)
2022
> type Name = Int
2123

2224
> data ErrorHandlerType
@@ -103,6 +105,9 @@ non-terminals = s..n
103105
terminals = n..m
104106
%eof = m
105107

108+
where n_nonterminals = n - 3 (including %starts)
109+
n_terminals = 1{-error-} + (m-n) + 1{-eof-} (including error and %eof)
110+
106111
These numbers are deeply magical, change at your own risk. Several
107112
other places rely on these being arranged as they are, including
108113
ProduceCode.lhs and the various HappyTemplates.
@@ -113,6 +118,10 @@ namespace, which are kept in the Grammar structure.
113118

114119
In hindsight, this was probably a bad idea.
115120

121+
In normal and GHC-based parsers, these numbers are also used in the
122+
generated grammar itself, except that the error token is mapped to -1.
123+
For array-based parsers, see the note in Tabular/LALR.lhs.
124+
116125
> startName, eofName, errorName, dummyName :: String
117126
> startName = "%start" -- with a suffix, like %start_1, %start_2 etc.
118127
> eofName = "%eof"
@@ -123,4 +132,24 @@ In hindsight, this was probably a bad idea.
123132
> firstStartTok = 3
124133
> dummyTok = 2
125134
> errorTok = 1
126-
> epsilonTok = 0
135+
> epsilonTok = 0
136+
137+
-----------------------------------------------------------------------------
138+
Replace $$ with an arbitrary string, being careful to avoid ".." and '.'.
139+
140+
> mapDollarDollar :: String -> Maybe (String -> String)
141+
> mapDollarDollar code0 = go code0 ""
142+
> where go code acc =
143+
> case code of
144+
> [] -> Nothing
145+
>
146+
> '"' :r -> case reads code :: [(String,String)] of
147+
> [] -> go r ('"':acc)
148+
> (s,r'):_ -> go r' (reverse (show s) ++ acc)
149+
> a:'\'' :r | isAlphaNum a -> go r ('\'':a:acc)
150+
> '\'' :r -> case reads code :: [(Char,String)] of
151+
> [] -> go r ('\'':acc)
152+
> (c,r'):_ -> go r' (reverse (show c) ++ acc)
153+
> '\\':'$':r -> go r ('$':acc)
154+
> '$':'$':r -> Just (\repl -> reverse acc ++ repl ++ r)
155+
> c:r -> go r (c:acc)

packages/tabular/LICENSE

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../LICENSE

packages/tabular/Setup.hs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

packages/tabular/happy-tabular.cabal

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: happy-tabular
2+
version: 1.21.0
3+
license: BSD2
4+
license-file: LICENSE
5+
copyright: (c) Andy Gill, Simon Marlow
6+
author: Andy Gill and Simon Marlow
7+
maintainer: Simon Marlow <[email protected]>
8+
bug-reports: https://github.com/simonmar/happy/issues
9+
stability: stable
10+
homepage: https://www.haskell.org/happy/
11+
category: Development
12+
cabal-version: >= 1.10
13+
build-type: Simple
14+
synopsis: Action and goto tables for happy
15+
16+
Description:
17+
Happy is a parser generator for Haskell.
18+
Happy-Tabular converts `Grammar`s, coming from
19+
a frontend, into LALR action and goto tables,
20+
which are further processed by a backend.
21+
22+
tested-with:
23+
GHC == 7.0.4
24+
GHC == 7.4.2
25+
GHC == 7.6.3
26+
GHC == 7.8.4
27+
GHC == 7.10.3
28+
GHC == 8.0.2
29+
GHC == 8.2.2
30+
GHC == 8.4.4
31+
GHC == 8.6.5
32+
GHC == 8.8.4
33+
GHC == 8.10.4
34+
GHC == 9.0.1
35+
36+
library
37+
hs-source-dirs: src
38+
39+
exposed-modules: Happy.Tabular,
40+
Happy.Tabular.First,
41+
Happy.Tabular.Info,
42+
Happy.Tabular.LALR,
43+
Happy.Tabular.NameSet
44+
build-depends: base < 5,
45+
array,
46+
containers >= 0.4.2,
47+
happy-grammar == 1.21.0
48+
49+
default-language: Haskell98
50+
default-extensions: CPP, MagicHash, FlexibleContexts, NamedFieldPuns
51+
ghc-options: -Wall

src/Tabular.lhs renamed to packages/tabular/src/Happy/Tabular.lhs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
> module Tabular (
1+
> module Happy.Tabular (
22
> Tables(..),
33
> genTables,
44
> SelectReductions,
55
> select_all_reductions,
66
> select_first_reduction
77
> ) where
88

9-
> import NameSet (NameSet)
10-
> import First
119
> import Happy.Grammar
12-
> import LALR
10+
> import Happy.Tabular.First
11+
> import Happy.Tabular.LALR
12+
> import Happy.Tabular.NameSet (NameSet)
1313

1414
> import Data.Array( Array, assocs, elems, (!) )
1515
> import Data.List ( nub )

src/First.lhs renamed to packages/tabular/src/Happy/Tabular/First.lhs

+14-4
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ Implementation of FIRST
44
(c) 1993-2001 Andy Gill, Simon Marlow
55
-----------------------------------------------------------------------------
66

7-
> module First ( mkFirst ) where
7+
> module Happy.Tabular.First ( mkFirst, mkClosure ) where
88

9-
> import GenUtils
10-
> import NameSet ( NameSet )
11-
> import qualified NameSet as Set
9+
> import Happy.Tabular.NameSet ( NameSet )
10+
> import qualified Happy.Tabular.NameSet as Set
1211
> import Happy.Grammar
1312
> import Data.IntSet (IntSet)
1413

@@ -21,6 +20,17 @@ Implementation of FIRST
2120
> | Set.member epsilonTok h = Set.delete epsilonTok h `Set.union` b
2221
> | otherwise = h
2322

23+
@mkClosure@ makes a closure, when given a comparison and iteration loop.
24+
Be careful, because if the functional always makes the object different,
25+
This will never terminate.
26+
27+
> mkClosure :: (a -> a -> Bool) -> (a -> a) -> a -> a
28+
> mkClosure eq f = match . iterate f
29+
> where
30+
> match (a:b:_) | a `eq` b = a
31+
> match (_:c) = match c
32+
> match [] = error "Can't happen: match []"
33+
2434
\subsection{Implementation of FIRST}
2535

2636
> mkFirst :: Grammar -> [Name] -> NameSet

src/Info.lhs renamed to packages/tabular/src/Happy/Tabular/Info.lhs

+12-6
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@ Generating info files.
44
(c) 1993-2001 Andy Gill, Simon Marlow
55
-----------------------------------------------------------------------------
66

7-
> module Info (genInfoFile) where
7+
> module Happy.Tabular.Info (genInfoFile) where
88

9-
> import Paths_happy ( version )
10-
> import LALR ( Lr0Item(..), Goto(..), LRAction(..), ActionTable, GotoTable )
11-
> import GenUtils ( str, interleave, interleave' )
129
> import Data.Set ( Set )
1310
> import qualified Data.Set as Set hiding ( Set )
1411
> import Happy.Grammar
12+
> import Happy.Tabular.LALR ( Lr0Item(..), LRAction(..), Goto(..), GotoTable, ActionTable )
1513

1614
> import Data.Array
1715
> import Data.List (nub)
18-
> import Data.Version ( showVersion )
16+
> import Data.Version ( Version, showVersion )
1917

2018
Produce a file of parser information, useful for debugging the parser.
2119

@@ -29,6 +27,7 @@ Produce a file of parser information, useful for debugging the parser.
2927
> -> String
3028
> -> [Int] -- unused rules
3129
> -> [String] -- unused terminals
30+
> -> Version
3231
> -> String
3332

3433
> genInfoFile items
@@ -38,7 +37,7 @@ Produce a file of parser information, useful for debugging the parser.
3837
> , non_terminals = nonterms
3938
> , token_names = env
4039
> })
41-
> action goto tokens conflictArray filename unused_rules unused_terminals
40+
> action goto tokens conflictArray filename unused_rules unused_terminals version
4241
> = (showHeader
4342
> . showConflicts
4443
> . showUnused
@@ -222,3 +221,10 @@ Produce a file of parser information, useful for debugging the parser.
222221
> = str "-----------------------------------------------------------------------------\n"
223222
> . str s
224223
> . str "\n-----------------------------------------------------------------------------\n"
224+
225+
> str :: String -> String -> String
226+
> str = showString
227+
> interleave :: String -> [String -> String] -> String -> String
228+
> interleave s = foldr (\a b -> a . str s . b) id
229+
> interleave' :: String -> [String -> String] -> String -> String
230+
> interleave' s = foldr1 (\a b -> a . str s . b)

0 commit comments

Comments
 (0)