Skip to content
This repository was archived by the owner on Apr 26, 2021. It is now read-only.

Commit 43e2d43

Browse files
committed
Merge branch 'refactor/parser' into development
2 parents 4a9e9a0 + 9ef82f8 commit 43e2d43

36 files changed

+2079
-717
lines changed

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"purescript.addNpmPath": true,
3+
"editor.tabSize": 2,
4+
"editor.rulers": [80,120]
5+
}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ Options:
150150
`opts.versionFlags` is non-empty and `opts.version` is not set.
151151
* `opts.helpFlags` - An array of flags that trigger the special help
152152
behavior: Print the full program help text and exit with code 0.
153+
* `opts.repeatableOptions` - Allow options to be repeated even if the spec does
154+
not explicitly allow this. This "loosens" up the parser to accept more input
155+
and makes for a more intuitive command line. _Please note:_ repeatability
156+
is still subject to chunking (use `opts.laxPlacement` to relax this further).
153157
* `opts.transforms.presolve` - an array of functions to be called prior to
154158
"solving" the input. This function takes the spec as it's only parameter.
155159
At this point, the spec is mostly untouched by neodoc with the exception of

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
"test:js": "mocha --compilers js:babel-register test-js",
1616
"test:purs": "pulp test",
1717
"test": "npm run -s test:purs && npm run -s test:js",
18-
"watch": "pulp -w --then 'npm run -s build && npm run -s test:js' test",
18+
"watch": "npm run -s watch:purs",
19+
"watch:all": "pulp -w test",
20+
"watch:purs": "pulp -w test",
1921
"watch:js": "mocha -w --compilers js:babel-register test-js",
2022
"minify": "uglifyjs dist/neodoc.purs.js > dist/neodoc.purs.min.js",
2123
"deps": "bower install",

src/Data/Foldable/Extra.purs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Data.Foldable.Extra where
2+
3+
import Prelude
4+
import Data.Maybe
5+
import Data.Foldable
6+
7+
-- | Try to find an element in a data structure which satisfies a predicate mapping.
8+
findMap :: forall a b f. Foldable f => (a -> Maybe b) -> f a -> Maybe b
9+
findMap p = foldl go Nothing
10+
where
11+
go Nothing x = p x
12+
go r _ = r

src/Data/NonEmpty/Extra.purs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,10 @@ fromList
3333
-> Maybe (NonEmpty List a)
3434
fromList (x:xs) = Just (x :| xs)
3535
fromList Nil = Nothing
36+
37+
fromList'
38+
:: a
39+
. Partial
40+
=> List a
41+
-> NonEmpty List a
42+
fromList' (x:xs) = x :| xs

src/Data/Pretty/Pretty.purs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ module Data.Pretty where
33
import Prelude
44
import Data.Tuple (Tuple(..))
55
import Data.Tuple.Nested ((/\))
6-
import Data.List (List)
6+
import Data.List (List, fromFoldable)
77
import Data.Map (Map)
8+
import Data.Set (Set)
89
import Data.Map as Map
910
import Data.Either
1011
import Data.StrMap (StrMap)
@@ -33,6 +34,9 @@ instance prettyStrMap :: (Pretty v) => Pretty (StrMap v) where
3334
pretty kvs = intercalate ", " $ StrMap.toList kvs <#> \(k /\ v) ->
3435
k <> " => " <> pretty v
3536

37+
instance prettySet :: (Pretty k) => Pretty (Set k) where
38+
pretty ks = pretty $ fromFoldable ks
39+
3640
instance prettyEither :: (Pretty e, Pretty a) => Pretty (Either e a) where
3741
pretty (Left e) = pretty e
3842
pretty (Right a) = pretty a

src/Debug/Profile.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ exports.timerStart = function () {
1111

1212
exports.timerEnd = function (start) {
1313
return function () {
14-
return process.hrtime(start)[1]/1000000;
14+
var hrTime = process.hrtime(start);
15+
return hrTime[0] * 1000 + hrTime[1] / 1000000
1516
};
1617
}

src/Debug/Profile.purs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module Debug.Profile where
22

33
import Prelude
44
import Debug.Trace
5+
import Data.Either
6+
import Data.Tuple.Nested
57
import Control.Monad.Eff
68
import Control.Monad.Eff.Console
79
import Control.Monad.Eff.Unsafe
@@ -24,6 +26,23 @@ profileA msg f =
2426
pure a
2527
else f unit
2628

29+
profileS :: a. String -> (Unit -> a) -> a
30+
profileS msg f =
31+
if _ENABLE_PROFILING_
32+
then
33+
let t' = unsafePerformEff timerStart
34+
c = \_->
35+
-- note: purescript appears to sort these assignments
36+
-- alphabetically, which means, we must name our variables
37+
-- accordingly. This depends on internal compiler behavior and
38+
-- may break w/ an update of purescript.
39+
let z = f unit
40+
t = unsafePerformEff $ timerEnd t'
41+
in z /\ t
42+
in case c unit of
43+
r /\ t -> trace (msg <> " (" <> (show t) <> " ms)") \_-> r
44+
else f unit
45+
2746
profileParser :: s m a. (Monad m) => String -> P.ParserT s m a -> P.ParserT s m a
2847
profileParser msg p = P.ParserT $ \s -> profileA msg \_ -> P.unParserT p s
2948

src/Neodoc/ArgParser/Arg.purs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
module Neodoc.ArgParser.Arg where
2+
3+
import Prelude
4+
import Data.Maybe
5+
import Data.Function (on)
6+
import Data.Generic
7+
import Data.Foldable (all)
8+
import Data.Pretty
9+
import Neodoc.Data.Layout
10+
import Neodoc.Value.RichValue
11+
import Neodoc.ArgKey
12+
import Neodoc.Data.SolvedLayout
13+
import Neodoc.Data.SolvedLayout as Solved
14+
15+
{-
16+
An argument data structure optimized for parsing.
17+
The idea is to cache as much as possible up-front,
18+
to avoid unnecessary traversals during the "hot"
19+
phases of the parse (i.e. permutation parsing).
20+
-}
21+
type Id = Int
22+
data Arg
23+
= Arg Id -- the unique id
24+
SolvedLayoutArg -- the wrapped arg
25+
ArgKey -- the (cached) arg key
26+
(Maybe RichValue) -- the fallback value for this argument
27+
Boolean -- is this argument optional?
28+
type ArgLayout = Layout Arg
29+
30+
derive instance genericArg :: Generic Arg
31+
32+
instance showArg :: Show Arg where
33+
show = gShow
34+
35+
instance prettyArg :: Pretty Arg where
36+
pretty (Arg i a _ _ o) =
37+
"#" <> show i <> ":"
38+
<> (if o then "[" else "")
39+
<> pretty a
40+
<> (if o then "]" else "")
41+
42+
instance eqArg :: Eq Arg where
43+
eq = eq `on` getId
44+
45+
getArg :: Arg -> SolvedLayoutArg
46+
getArg (Arg _ x _ _ _) = x
47+
48+
getArgKey :: Arg -> ArgKey
49+
getArgKey (Arg _ _ k _ _) = k
50+
51+
getId :: Arg -> Id
52+
getId (Arg i _ _ _ _) = i
53+
54+
setId :: Id -> Arg -> Arg
55+
setId i (Arg _ a k mV o) = Arg i a k mV o
56+
57+
isOptional :: Arg -> Boolean
58+
isOptional (Arg _ _ _ _ o) = o
59+
60+
getFallback :: Arg -> Maybe RichValue
61+
getFallback (Arg _ _ _ mV _) = mV
62+
63+
setRepeatable :: Boolean -> ArgLayout -> ArgLayout
64+
setRepeatable b (Group o _ xs) = Group o b xs
65+
setRepeatable b (Elem x) = Elem $ setElemRepeatable b x
66+
67+
setElemRepeatable :: Boolean -> Arg -> Arg
68+
setElemRepeatable b (Arg i x k mV o) = Arg i (Solved.setElemRepeatable b x) k mV o
69+
70+
isFreeLayout :: ArgLayout -> Boolean
71+
isFreeLayout (Elem (Arg _ x _ _ _)) = Solved.isFreeElem x
72+
isFreeLayout (Group _ _ xs) = all (all isFreeLayout) xs
73+
74+
isFree :: Arg -> Boolean
75+
isFree (Arg _ x _ _ _) = Solved.isFreeElem x
76+
77+
isRepeatable :: ArgLayout -> Boolean
78+
isRepeatable (Elem x) = isArgRepeatable x
79+
isRepeatable (Group _ r _) = r
80+
81+
isArgRepeatable :: Arg -> Boolean
82+
isArgRepeatable (Arg _ x _ _ _) = Solved.isElemRepeatable x
83+
84+
isOptionElem :: ArgLayout -> Boolean
85+
isOptionElem (Elem x) = isOption x
86+
isOptionElem _ = false
87+
88+
isOption :: Arg -> Boolean
89+
isOption (Arg _ x _ _ _) = Solved.isOption x

src/Neodoc/ArgParser/Debug.purs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
module Neodoc.ArgParser.Debug where
2+
3+
import Prelude
4+
import Debug.Trace hiding (trace)
5+
import Data.String as String
6+
import Data.Pretty
7+
import Data.List (List)
8+
import Data.List.Lazy as LL
9+
import Neodoc.ArgParser.Type
10+
import Neodoc.ArgParser.Token
11+
12+
_ENABLE_DEBUG_ :: Boolean
13+
_ENABLE_DEBUG_ = false
14+
15+
trace :: r. Int -> (List PositionedToken -> String) -> ArgParser r Unit
16+
trace l f = if _ENABLE_DEBUG_
17+
then do
18+
input <- getInput
19+
state <- getState
20+
globalState <- getGlobalState
21+
traceA $ indent l <> stateLabel state globalState <> (f input)
22+
else pure unit
23+
24+
traceError :: r a. Int -> String -> ArgParser r a -> ArgParser r a
25+
traceError l s = catch' \st e ->
26+
trace l (\_ -> "! " <> s <> ": " <> pretty e)
27+
*> setState st
28+
*> throw e
29+
30+
traceInput :: r. ArgParser r Unit
31+
traceInput = traceA =<< pretty <$> getInput
32+
33+
indent :: Int -> String
34+
indent l = String.fromCharArray $ LL.toUnfoldable $ LL.take (l) $ LL.repeat ' '
35+
36+
traceBracket
37+
:: r a
38+
. (Pretty a)
39+
=> Int
40+
-> String
41+
-> ArgParser r a
42+
-> ArgParser r a
43+
traceBracket l label p = do
44+
input <- getInput
45+
state <- getState
46+
globalState <- getGlobalState
47+
trace l \_ ->
48+
stateLabel state globalState <> " parsing " <> label <> " (input: " <> pretty input <> ")"
49+
output <- traceError l (stateLabel state globalState <> " failed to parse " <> label) p
50+
input' <- getInput
51+
state' <- getState
52+
globalState' <- getGlobalState
53+
trace l \_ ->
54+
stateLabel state' globalState' <> " successfully parsed " <> label <> "!"
55+
<> " (output: " <> pretty output <> ")"
56+
<> " (new input: " <> pretty input' <> ")"
57+
pure output
58+
59+
stateLabel :: ParseState -> GlobalParseState -> String
60+
stateLabel { hasTerminated, depth } { deepestError } =
61+
(if hasTerminated then "" else "·")
62+
-- <> "(" <> show depth <> ")"
63+
-- <> "(dE = " <> show (pretty <$> deepestError) <> ")

0 commit comments

Comments
 (0)