@@ -1,20 +1,30 @@
1+{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-}
1−module Parse.Helpers where
2+module Parse.Helpers
3+ ( expecting, failure, anyUntil
5+ , IParser, SourceM, iParse
6+ , var, lowVar, capVar, rLabel, reserved, reserveds
7+ , equals, rightArrow, hasType
9+ , followedBy, comma, commaSep1, commaSep
10+ , pipeSep1, consSep1, dotSep1, spaceSep1, spacePrefix, constrainedSpacePrefix
11+ , braces, parens, brackets
13+ , getMyPosition, addLocation, located
14+ , whitespace, freshLine, simpleNewline, newline, spaces
15+ , forcedWS, padded, dumbWhitespace, docComment
3−import Prelude hiding (until)
4−import Control.Monad (join)
5import Control.Monad.State (State)
19import Control.Monad.State (State)
6import Data.Char (isUpper)
20import Data.Char (isUpper)
7import qualified Data.Map as Map
21import qualified Data.Map as Map
8−import qualified Language.GLSL.Parser as GLP
9−import qualified Language.GLSL.Syntax as GLS
10−import Text.Parsec hiding (newline, spaces, State)
22+import Text.Parsec hiding (State, newline, space, spaces)
11import Text.Parsec.Indent (indented, runIndent)
23import Text.Parsec.Indent (indented, runIndent)
12−import qualified Text.Parsec.Token as T
14import qualified AST.Declaration as Decl
25import qualified AST.Declaration as Decl
15import qualified AST.Expression.General as E
26import qualified AST.Expression.General as E
16import qualified AST.Expression.Source as Source
27import qualified AST.Expression.Source as Source
17−import qualified AST.Literal as L
18import qualified AST.Variable as Variable
28import qualified AST.Variable as Variable
19import qualified Reporting.Annotation as A
29import qualified Reporting.Annotation as A
20import qualified Reporting.Error.Syntax as Syntax
30import qualified Reporting.Error.Syntax as Syntax
@@ -22,33 +32,39 @@ import qualified Reporting.Region as R
25−reserveds :: [String]
35+-- ERROR HELP
27− [ "if", "then", "else"
32− , "import", "exposing"
38+expecting :: String -> IParser a -> IParser a
43+failure :: String -> IParser a
42−expecting = flip (<?>)
51+anyUntil :: IParser String -> IParser String
56+ end <|> (:) <$> anyChar <*> go
63+type IParser a = ParsecT String OpTable SourceM a
49type OpTable = Map.Map String (Int, Decl.Assoc)
65type OpTable = Map.Map String (Int, Decl.Assoc)
50type SourceM = State SourcePos
67type SourceM = State SourcePos
51−type IParser a = ParsecT String OpTable SourceM a
54iParse :: IParser a -> String -> Either ParseError a
70iParse :: IParser a -> String -> Either ParseError a
@@ -61,8 +77,10 @@ iParseWithTable sourceName table aParser input =
61 runIndent sourceName $ runParserT aParser table sourceName input
77 runIndent sourceName $ runParserT aParser table sourceName input
64-- VARIABLES
81-- VARIABLES
66var :: IParser String
84var :: IParser String
68 makeVar (letter <|> char '_') <?> "a name"
86 makeVar (letter <|> char '_') <?> "a name"
@@ -78,14 +96,9 @@ capVar =
78 makeVar upper <?> "an upper case name"
96 makeVar upper <?> "an upper case name"
81−qualifiedVar :: IParser String
83− do vars <- many ((++) <$> capVar <*> string ".")
84− (++) (concat vars) <$> lowVar
87rLabel :: IParser String
99rLabel :: IParser String
88−rLabel = lowVar
100+rLabel =
91innerVarChar :: IParser Char
104innerVarChar :: IParser Char
@@ -118,6 +131,19 @@ reserved word =
134+reserveds :: [String]
136+ [ "if", "then", "else"
141+ , "import", "exposing"
122-- COMMON SYMBOLS
148-- COMMON SYMBOLS
@@ -137,6 +163,11 @@ hasType =
137 string ":" <?> "the \"has type\" symbol ':'"
163 string ":" <?> "the \"has type\" symbol ':'"
170+commitIf :: IParser a -> IParser b -> IParser b
140commitIf check p =
171commitIf check p =
141 commit <|> try p
172 commit <|> try p
@@ -144,10 +175,6 @@ commitIf check p =
144 try (lookAhead check) >> p
175 try (lookAhead check) >> p
151spaceySepBy1 :: IParser b -> IParser a -> IParser [a]
178spaceySepBy1 :: IParser b -> IParser a -> IParser [a]
152spaceySepBy1 sep parser =
179spaceySepBy1 sep parser =
153 do value <- parser
180 do value <- parser
@@ -174,11 +201,6 @@ commaSep =
174 option [] . commaSep1
201 option [] . commaSep1
177−semiSep1 :: IParser a -> IParser [a]
179− spaceySepBy1 (char ';' <?> "a semicolon ';'")
182pipeSep1 :: IParser a -> IParser [a]
204pipeSep1 :: IParser a -> IParser [a]
183pipeSep1 =
205pipeSep1 =
184 spaceySepBy1 (char '|' <?> "a vertical bar '|'")
206 spaceySepBy1 (char '|' <?> "a vertical bar '|'")
@@ -199,10 +221,12 @@ spaceSep1 p =
199 (:) <$> p <*> spacePrefix p
221 (:) <$> p <*> spacePrefix p
224+spacePrefix :: IParser a -> IParser [a]
202spacePrefix p =
225spacePrefix p =
203 constrainedSpacePrefix p (\_ -> return ())
226 constrainedSpacePrefix p (\_ -> return ())
229+constrainedSpacePrefix :: IParser a -> (String -> IParser ()) -> IParser [a]
206constrainedSpacePrefix parser constraint =
230constrainedSpacePrefix parser constraint =
207 many $ choice
231 many $ choice
208 [ try (spacing >> lookAhead (oneOf "[({")) >> parser
232 [ try (spacing >> lookAhead (oneOf "[({")) >> parser
@@ -219,20 +243,13 @@ constrainedSpacePrefix parser constraint =
219-- SURROUNDED BY
243-- SURROUNDED BY
246+followedBy :: IParser a -> IParser b -> IParser a
222followedBy a b =
247followedBy a b =
223 do x <- a
248 do x <- a
228−betwixt :: Char -> Char -> IParser a -> IParser a
232− char b <?> "a closing '" ++ [b] ++ "'"
236surround :: Char -> Char -> String -> IParser a -> IParser a
253surround :: Char -> Char -> String -> IParser a -> IParser a
237surround a z name p = do
254surround a z name p = do
@@ -420,272 +437,3 @@ closeComment =
420 [ try (string "-}") <?> "the end of a comment -}"
437 [ try (string "-}") <?> "the end of a comment -}"
421 , concat <$> sequence [ try (string "{-"), closeComment, closeComment ]
438 , concat <$> sequence [ try (string "{-"), closeComment, closeComment ]
436−until :: IParser a -> IParser b -> IParser b
440− go = end <|> (p >> go)
443−anyUntil :: IParser String -> IParser String
448− end <|> (:) <$> anyChar <*> go
451−ignoreUntil :: IParser a -> IParser (Maybe a)
460− [ try (ignore chr) <|> ignore str
461− , ignore multiComment
469− , filler `until` choice [ const Nothing <$> eof, newline >> go ]
473−onFreshLines :: (a -> b -> b) -> b -> IParser a -> IParser b
474−onFreshLines insert init thing =
478− do optionValue <- ignoreUntil thing
480− Nothing -> return values
481− Just v -> go (insert v values)
484−withSource :: IParser a -> IParser (String, a)
486− do start <- getParserState
488− endPos <- getPosition
489− setParserState start
490− raw <- anyUntilPos endPos
491− return (raw, result)
494−anyUntilPos :: SourcePos -> IParser String
496− do currentPos <- getPosition
497− if currentPos == pos
499− else (:) <$> anyChar <*> anyUntilPos pos
506−shader :: IParser (String, L.GLShaderTipe)
508− do try (string "[glsl|")
509− rawSrc <- closeShader id
510− case glSource rawSrc of
511− Left err -> parserFail . show $ err
512− Right tipe -> return (rawSrc, tipe)
515−closeShader :: (String -> a) -> IParser a
516−closeShader builder =
518− [ do try (string "|]")
521− closeShader (builder . (c:))
525−glSource :: String -> Either ParseError L.GLShaderTipe
527− case GLP.parse src of
529− Right (GLS.TranslationUnit decls) ->
530− map extractGLinputs decls
532− |> foldr addGLinput emptyDecls
537− emptyDecls = L.GLShaderTipe Map.empty Map.empty Map.empty
539− addGLinput (qual,tipe,name) glDecls =
542− glDecls { L.attribute = Map.insert name tipe $ L.attribute glDecls }
545− glDecls { L.uniform = Map.insert name tipe $ L.uniform glDecls }
548− glDecls { L.varying = Map.insert name tipe $ L.varying glDecls }
550− _ -> error "Should never happen due to below filter"
552− extractGLinputs decl =
555− (GLS.InitDeclaration
558− (Just (GLS.TypeQualSto qual))
559− (GLS.TypeSpec _prec (GLS.TypeSpecNoPrecision tipe _mexpr1))))
560− [GLS.InitDecl name _mexpr2 _mexpr3]
562− case elem qual [GLS.Attribute, GLS.Varying, GLS.Uniform] of
566− GLS.Int -> return (qual, L.Int,name)
567− GLS.Float -> return (qual, L.Float,name)
568− GLS.Vec2 -> return (qual, L.V2,name)
569− GLS.Vec3 -> return (qual, L.V3,name)
570− GLS.Vec4 -> return (qual, L.V4,name)
571− GLS.Mat4 -> return (qual, L.M4,name)
572− GLS.Sampler2D -> return (qual, L.Texture,name)
578−-- STRINGS AND CHARACTERS
581−str :: IParser String
583− expecting "a string like \"hello\"" $
584− do charSeq <- choice [ multiStr, singleStr ]
585− either (fail . show) return $
586− processAs T.stringLiteral ('"' : charSeq ++ "\"")
589−delimitedSequence :: IParser a -> IParser String -> IParser String
590−delimitedSequence quote insides =
592− concat <$> manyTill insides quote
595−multiStr :: IParser String
597− delimitedSequence (try (string "\"\"\"")) multilineStringChar
600−singleStr :: IParser String
602− delimitedSequence (char '"') (charWithin '"')
607− expecting "a character like 'x'" $
609− charSeq <- concat <$> many1 (charWithin '\'') <?> "a character"
610− case processAs T.charLiteral ("'" ++ charSeq ++ "'") of
617− "Elm uses double quotes for strings. Switch\
618− \ the ' to \" on both ends of the string and\
619− \ you should be all set!"
626−charWithin :: Char -> IParser String
630− , (:[]) <$> satisfy (/= delim)
634−multilineStringChar :: IParser String
635−multilineStringChar =
636− do notFollowedBy (string "\"\"\"")
640− , escapeQuotes <$> anyChar
644−escapeQuotes :: Char -> String
646− if c == '\"' then "\\\"" else [c]
649−newlineChar :: IParser String
652− [ char '\n' >> return "\\n"
653− , char '\r' >> return "\\r"
657−escaped :: Char -> IParser String
661− c <- char '\\' <|> char delim
666− :: (T.GenTokenParser String u SourceM -> IParser a)
668− -> Either ParseError a
669−processAs processor string =
670− iParse (processor lexer) string
672− lexer :: T.GenTokenParser String u SourceM
674− T.makeTokenParser elmDef
676− -- I don't know how many of these are necessary for charLiteral/stringLiteral
677− elmDef :: T.GenLanguageDef String u SourceM
680− { T.commentStart = "{-"
681− , T.commentEnd = "-}"
682− , T.commentLine = "--"
683− , T.nestedComments = True
684− , T.identStart = undefined
685− , T.identLetter = undefined
686− , T.opStart = undefined
687− , T.opLetter = undefined
688− , T.reservedNames = reserveds
689− , T.reservedOpNames = [":", "->", "|"]
690− , T.caseSensitive = True