git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
First attempt at whitespace sensitive syntax
commit6b2d16b06eafaccc91c4c99c5868fb93552a15db authorPhil Freeman <paf31@cantab.net> dateSun 13 Oct 2013, 17:48 (13 years ago) parent0c961be
5 files changed+122−106
PureScript.cabal+6−5 src/PureScript/Parser/Common.hs+51−28 src/PureScript/Parser/Declarations.hs+14−24 src/PureScript/Parser/Types.hs+15−14 src/PureScript/Parser/Values.hs+36−35
PureScript.cabal+6−5
@@ -11,10 +11,11 @@ synopsis: PureScript Programming Language Compiler
1111description: A small compile-to-JS language with extensible records and type-safe blocks
1212author: Phil Freeman <paf31@cantab.net>
1313data-dir: ""
14−
14+
1515library
1616 build-depends: base -any, syb -any, cmdtheline -any,
17− containers -any, mtl -any, parsec -any, utf8-string -any
17+ containers -any, mtl -any, parsec -any, utf8-string -any,
18+ indents -any
1819 exposed-modules: PureScript
1920 exposed: True
2021 buildable: True
@@ -28,14 +29,14 @@ library
2829 PureScript.Parser.Types PureScript.Parser.Values
2930 PureScript.TypeChecker.Kinds PureScript.TypeChecker.Monad
3031 PureScript.TypeChecker.Types
31−
32+
3233executable psc
3334 build-depends: base -any, cmdtheline -any, containers -any,
34− mtl -any, parsec -any, utf8-string -any
35+ mtl -any, parsec -any, utf8-string -any, indents -any
3536 main-is: Main.hs
3637 buildable: True
3738 hs-source-dirs: src
3839 other-modules: PureScript.Names PureScript.TypeChecker.Synonyms
3940 PureScript.CodeGen.Externs PureScript.CodeGen.JS
4041 PureScript.CodeGen.Common.Gen PureScript.CodeGen.Common
41−
42+
src/PureScript/Parser/Common.hs+51−28
@@ -16,14 +16,14 @@ module PureScript.Parser.Common where
1616
1717import Control.Applicative
1818import qualified Text.Parsec as P
19+import qualified Text.Parsec.Indent as I
1920import qualified Text.Parsec.Token as PT
2021import qualified Text.Parsec.Language as PL
2122
2223import PureScript.Names
2324
24−langDef = PL.haskellStyle
25− { PT.identStart = P.lower <|> P.char '_'
26− , PT.reservedNames = [ "case"
25+langDef = PT.LanguageDef
26+ { PT.reservedNames = [ "case"
2727 , "data"
2828 , "type"
2929 , "var"
@@ -39,34 +39,57 @@ langDef = PL.haskellStyle
3939 , "forall" ]
4040 , PT.reservedOpNames = [ "!", "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"
4141 , "==", "!=", "&", "^", "|", "&&", "||" ]
42+ , PT.commentStart = "{-"
43+ , PT.commentEnd = "-}"
44+ , PT.commentLine = "--"
45+ , PT.nestedComments = True
46+ , PT.identStart = P.lower <|> P.oneOf "_$"
47+ , PT.identLetter = P.alphaNum <|> P.oneOf "_'"
48+ , PT.opStart = P.oneOf ":#?@\\"
49+ , PT.opLetter = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
50+ , PT.caseSensitive = True
4251 }
4352
44−tokenParser = PT.makeTokenParser langDef
45−lexeme = PT.lexeme tokenParser
46−identifier = PT.identifier tokenParser
47−reserved = PT.reserved tokenParser
48−operator = PT.operator tokenParser
49−stringLiteral = PT.stringLiteral tokenParser
50−natural = PT.natural tokenParser
51−naturalOrFloat = PT.naturalOrFloat tokenParser
52−whiteSpace = PT.whiteSpace tokenParser
53−parens = PT.parens tokenParser
54−braces = PT.braces tokenParser
55−angles = PT.angles tokenParser
56−brackets = PT.brackets tokenParser
57−squares = PT.squares tokenParser
58−semi = PT.semi tokenParser
59−comma = PT.comma tokenParser
60−colon = PT.colon tokenParser
61−dot = PT.dot tokenParser
62−semiSep = PT.semiSep tokenParser
63−semiSep1 = PT.semiSep1 tokenParser
64−commaSep = PT.commaSep tokenParser
65−commaSep1 = PT.commaSep1 tokenParser
53+tokenParser = PT.makeTokenParser langDef
54+
55+whiteSpace = P.skipMany $ (P.oneOf " \t" >> return ()) <|> P.try (P.skipMany1 (P.oneOf "\r\n")) >> I.indented <|> P.try lineComment <|> P.try blockComment
56+
57+lineComment = do
58+ P.string $ PT.commentLine langDef
59+ P.skipMany $ P.satisfy (/= '\n')
60+ I.indented
61+
62+blockComment = do
63+ P.string $ PT.commentStart langDef
64+ P.manyTill P.anyChar $ P.try $ P.string $ PT.commentEnd langDef
65+ return ()
66+
67+lexeme p = p <* whiteSpace
68+identifier = lexeme $ PT.identifier tokenParser
69+reserved s = lexeme $ PT.reserved tokenParser s
70+operator = lexeme $ PT.operator tokenParser
71+stringLiteral = lexeme $ PT.stringLiteral tokenParser
72+natural = lexeme $ PT.natural tokenParser
73+naturalOrFloat = lexeme $ PT.naturalOrFloat tokenParser
74+
75+semi = lexeme $ PT.semi tokenParser
76+comma = lexeme $ PT.comma tokenParser
77+colon = lexeme $ PT.colon tokenParser
78+dot = lexeme $ PT.dot tokenParser
79+
80+semiSep p = P.sepBy p semi
81+semiSep1 p = P.sepBy1 p semi
82+commaSep p = P.sepBy p comma
83+commaSep1 p = P.sepBy1 p comma
84+
85+parens p = lexeme (P.char '(') *> lexeme p <* lexeme (P.char ')')
86+braces p = lexeme (P.char '{') *> lexeme p <* lexeme (P.char '}')
87+angles p = lexeme (P.char '<') *> lexeme p <* lexeme (P.char '>')
88+squares p = lexeme (P.char '[') *> lexeme p <* lexeme (P.char ']')
6689
6790tick = lexeme (P.char '`')
6891
69−properName :: P.Parsec String u String
92+properName :: I.IndentParser String u String
7093properName = lexeme $ P.try properName'
7194 where
7295 properName' = (:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name"
@@ -80,8 +103,8 @@ fold first more combine = do
80103 bs <- P.many more
81104 return $ foldl combine a bs
82105
83−parseIdent :: P.Parsec String () Ident
106+parseIdent :: I.IndentParser String () Ident
84107parseIdent = (Ident <$> identifier) <|> (Op <$> parens operator)
85108
86−parseIdentInfix :: P.Parsec String () Ident
109+parseIdentInfix :: I.IndentParser String () Ident
87110parseIdentInfix = (Ident <$> P.between tick tick identifier) <|> (Op <$> operator)
src/PureScript/Parser/Declarations.hs+14−24
@@ -22,8 +22,11 @@ import Data.List
2222import Data.Maybe
2323import Data.Function
2424import Control.Applicative
25−import qualified Text.Parsec as P
2625import Control.Arrow (Arrow(..))
26+import Control.Monad.State
27+import qualified Text.Parsec as P
28+import qualified Text.Parsec.Pos as P
29+import qualified Text.Parsec.Indent as I
2730
2831import PureScript.Values
2932import PureScript.Types
@@ -32,7 +35,7 @@ import PureScript.Declarations
3235import PureScript.Parser.Values
3336import PureScript.Parser.Types
3437
35−parseDataDeclaration :: P.Parsec String () Declaration
38+parseDataDeclaration :: I.IndentParser String () Declaration
3639parseDataDeclaration = do
3740 reserved "data"
3841 name <- properName
@@ -41,19 +44,19 @@ parseDataDeclaration = do
4144 ctors <- P.sepBy1 ((,) <$> properName <*> P.optionMaybe parseType) (lexeme $ P.char '|')
4245 return $ DataDeclaration name tyArgs ctors
4346
44−parseTypeDeclaration :: P.Parsec String () Declaration
47+parseTypeDeclaration :: I.IndentParser String () Declaration
4548parseTypeDeclaration = TypeDeclaration <$> parseIdent <*> (lexeme (P.string "::") *> parsePolyType)
4649
47−parseTypeSynonymDeclaration :: P.Parsec String () Declaration
50+parseTypeSynonymDeclaration :: I.IndentParser String () Declaration
4851parseTypeSynonymDeclaration = TypeSynonymDeclaration <$> (reserved "type" *> properName) <*> many identifier <*> (lexeme (P.char '=') *> parseType)
4952
50−parseValueDeclaration :: P.Parsec String () Declaration
53+parseValueDeclaration :: I.IndentParser String () Declaration
5154parseValueDeclaration = ValueDeclaration <$> parseIdent <*> (lexeme (P.char '=') *> parseValue)
5255
53−parseExternDeclaration :: P.Parsec String () Declaration
56+parseExternDeclaration :: I.IndentParser String () Declaration
5457parseExternDeclaration = ExternDeclaration <$> (reserved "extern" *> parseIdent) <*> (lexeme (P.string "::") *> parsePolyType)
5558
56−parseDeclaration :: P.Parsec String () Declaration
59+parseDeclaration :: I.IndentParser String () Declaration
5760parseDeclaration = P.choice $ map P.try
5861 [ parseDataDeclaration
5962 , parseTypeDeclaration
@@ -61,22 +64,9 @@ parseDeclaration = P.choice $ map P.try
6164 , parseValueDeclaration
6265 , parseExternDeclaration ]
6366
64−parseDeclarations :: String -> Either P.ParseError [Declaration]
65−parseDeclarations = fmap catMaybes . mapM (P.parse (whiteSpace *> (P.optionMaybe parseDeclaration <* whiteSpace) <* P.eof) "Declaration") . splitFileIntoDeclarations
66−
67−isIndented :: String -> Bool
68−isIndented = any isSpace . take 1
69−
70−splitFileIntoDeclarations :: String -> [String]
71−splitFileIntoDeclarations = reverse . map (dropWhile isSpace . unlines . reverse) . go [] [] . lines
72− where
73− go [] sss [] = sss
74− go ss sss [] = ss:sss
75− go ss sss (s:rest)
76− | all isSpace s = go ss sss rest
77− | isIndented s = go (s:ss) sss rest
78− | null ss = go [s] sss rest
79− | otherwise = go [s] (ss:sss) rest
80−
67+parseManyDeclarations :: I.IndentParser String () [Declaration]
68+parseManyDeclarations = I.block $ I.withPos parseDeclaration
8169
70+parseDeclarations :: String -> Either P.ParseError [Declaration]
71+parseDeclarations = flip evalState (P.initialPos "Declarations") . P.runPT parseManyDeclarations () "Declarations"
8272
src/PureScript/Parser/Types.hs+15−14
@@ -22,37 +22,38 @@ import PureScript.Types
2222import PureScript.Parser.Common
2323import Control.Applicative
2424import qualified Text.Parsec as P
25+import qualified Text.Parsec.Indent as I
2526import Control.Arrow (Arrow(..))
2627
27−parseNumber :: P.Parsec String () Type
28+parseNumber :: I.IndentParser String () Type
2829parseNumber = const Number <$> P.string "Number"
2930
30−parseString :: P.Parsec String () Type
31+parseString :: I.IndentParser String () Type
3132parseString = const String <$> P.string "String"
3233
33−parseBoolean :: P.Parsec String () Type
34+parseBoolean :: I.IndentParser String () Type
3435parseBoolean = const Boolean <$> P.string "Boolean"
3536
36−parseArray :: P.Parsec String () Type
37+parseArray :: I.IndentParser String () Type
3738parseArray = squares $ Array <$> parseType
3839
39−parseObject :: P.Parsec String () Type
40+parseObject :: I.IndentParser String () Type
4041parseObject = braces $ Object <$> parseRow
4142
42−parseFunction :: P.Parsec String () Type
43+parseFunction :: I.IndentParser String () Type
4344parseFunction = do
4445 args <- lexeme $ parens $ commaSep parseType
4546 lexeme $ P.string "->"
4647 resultType <- parseType
4748 return $ Function args resultType
4849
49−parseTypeVariable :: P.Parsec String () Type
50+parseTypeVariable :: I.IndentParser String () Type
5051parseTypeVariable = TypeVar <$> identifier
5152
52−parseTypeConstructor :: P.Parsec String () Type
53+parseTypeConstructor :: I.IndentParser String () Type
5354parseTypeConstructor = TypeConstructor <$> properName
5455
55−parseTypeAtom :: P.Parsec String () Type
56+parseTypeAtom :: I.IndentParser String () Type
5657parseTypeAtom = P.choice $ map P.try
5758 [ parseNumber
5859 , parseString
@@ -64,20 +65,20 @@ parseTypeAtom = P.choice $ map P.try
6465 , parseTypeConstructor
6566 , parens parseType ]
6667
67−parsePolyType :: P.Parsec String () PolyType
68+parsePolyType :: I.IndentParser String () PolyType
6869parsePolyType = PolyType <$> (P.option [] (reserved "forall" *> many identifier <* dot))
6970 <*> parseType
7071
71−parseType :: P.Parsec String () Type
72+parseType :: I.IndentParser String () Type
7273parseType = fold (lexeme parseTypeAtom) (lexeme parseTypeAtom) TypeApp
7374
74−parseNameAndType :: P.Parsec String () (String, Type)
75+parseNameAndType :: I.IndentParser String () (String, Type)
7576parseNameAndType = (,) <$> (identifier <* lexeme (P.string "::")) <*> parseType
7677
77−parseRowEnding :: P.Parsec String () Row
78+parseRowEnding :: I.IndentParser String () Row
7879parseRowEnding = P.option REmpty (RowVar <$> (lexeme (P.char '|') *> identifier))
7980
80−parseRow :: P.Parsec String () Row
81+parseRow :: I.IndentParser String () Row
8182parseRow = fromList <$> semiSep parseNameAndType <*> parseRowEnding
8283 where
8384 fromList :: [(String, Type)] -> Row -> Row
src/PureScript/Parser/Values.hs+36−35
@@ -21,38 +21,39 @@ import PureScript.Values
2121import qualified PureScript.Parser.Common as C
2222import Control.Applicative
2323import qualified Text.Parsec as P
24+import qualified Text.Parsec.Indent as I
2425import Text.Parsec.Expr
2526import Control.Monad
2627import Control.Arrow (Arrow(..))
2728import PureScript.Parser.Types
2829import PureScript.Types
2930
30−booleanLiteral :: P.Parsec String () Bool
31+booleanLiteral :: I.IndentParser String () Bool
3132booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)
3233
33−parseNumericLiteral :: P.Parsec String () Value
34+parseNumericLiteral :: I.IndentParser String () Value
3435parseNumericLiteral = NumericLiteral <$> C.naturalOrFloat
3536
36−parseStringLiteral :: P.Parsec String () Value
37+parseStringLiteral :: I.IndentParser String () Value
3738parseStringLiteral = StringLiteral <$> C.stringLiteral
3839
39−parseBooleanLiteral :: P.Parsec String () Value
40+parseBooleanLiteral :: I.IndentParser String () Value
4041parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
4142
42−parseArrayLiteral :: P.Parsec String () Value
43+parseArrayLiteral :: I.IndentParser String () Value
4344parseArrayLiteral = ArrayLiteral <$> (C.squares $ C.commaSep parseValue)
4445
45−parseObjectLiteral :: P.Parsec String () Value
46+parseObjectLiteral :: I.IndentParser String () Value
4647parseObjectLiteral = ObjectLiteral <$> (C.braces $ C.commaSep parseIdentifierAndValue)
4748
48−parseIdentifierAndValue :: P.Parsec String () (String, Value)
49+parseIdentifierAndValue :: I.IndentParser String () (String, Value)
4950parseIdentifierAndValue = do
5051 name <- C.lexeme C.identifier
5152 C.colon
5253 value <- parseValue
5354 return (name, value)
5455
55−parseAbs :: P.Parsec String () Value
56+parseAbs :: I.IndentParser String () Value
5657parseAbs = do
5758 C.lexeme $ P.char '\\'
5859 args <- C.commaSep C.parseIdent
@@ -60,27 +61,27 @@ parseAbs = do
6061 value <- parseValue
6162 return $ Abs args value
6263
63−parseApp :: P.Parsec String () Value
64+parseApp :: I.IndentParser String () Value
6465parseApp = App <$> parseValue
6566 <*> (C.parens $ C.commaSep parseValue)
6667
67−parseVar :: P.Parsec String () Value
68+parseVar :: I.IndentParser String () Value
6869parseVar = Var <$> C.parseIdent
6970
70−parseConstructor :: P.Parsec String () Value
71+parseConstructor :: I.IndentParser String () Value
7172parseConstructor = Constructor <$> C.properName
7273
73−parseCase :: P.Parsec String () Value
74+parseCase :: I.IndentParser String () Value
7475parseCase = Case <$> P.between (C.reserved "case") (C.reserved "of") parseValue
7576 <*> C.braces (C.semiSep parseCaseAlternative)
7677
77−parseCaseAlternative :: P.Parsec String () (Binder, Value)
78+parseCaseAlternative :: I.IndentParser String () (Binder, Value)
7879parseCaseAlternative = (,) <$> (parseBinder <* C.lexeme (P.string "->")) <*> parseValue
7980
80−parseBlock :: P.Parsec String () Value
81+parseBlock :: I.IndentParser String () Value
8182parseBlock = Block <$> (C.braces $ P.many (parseStatement True))
8283
83−parseValueAtom :: P.Parsec String () Value
84+parseValueAtom :: I.IndentParser String () Value
8485parseValueAtom = P.choice $ map P.try
8586 [ parseNumericLiteral
8687 , parseStringLiteral
@@ -94,7 +95,7 @@ parseValueAtom = P.choice $ map P.try
9495 , parseCase
9596 , C.parens parseValue ]
9697
97−parseValue :: P.Parsec String () Value
98+parseValue :: I.IndentParser String () Value
9899parseValue = buildExpressionParser operators $ C.fold (C.lexeme typedValue) (C.lexeme funArgs) App
99100 where
100101 typedValue = C.augment parseValueAtom parseTypeAnnotation TypedValue
@@ -128,7 +129,7 @@ parseValue = buildExpressionParser operators $ C.fold (C.lexeme typedValue) (C.l
128129 , [ Infix (C.lexeme (P.string "||") >> return (Binary Or)) AssocRight ]
129130 ]
130131
131−parseVariableIntroduction :: Bool -> P.Parsec String () Statement
132+parseVariableIntroduction :: Bool -> I.IndentParser String () Statement
132133parseVariableIntroduction requireSemi = do
133134 C.reserved "var"
134135 name <- C.parseIdent
@@ -137,7 +138,7 @@ parseVariableIntroduction requireSemi = do
137138 when requireSemi (void C.semi)
138139 return $ VariableIntroduction name value
139140
140−parseAssignment :: Bool -> P.Parsec String () (Statement)
141+parseAssignment :: Bool -> I.IndentParser String () (Statement)
141142parseAssignment requireSemi = do
142143 tgt <- parseAssignmentTarget
143144 C.lexeme $ P.char '='
@@ -145,14 +146,14 @@ parseAssignment requireSemi = do
145146 when requireSemi (void C.semi)
146147 return $ Assignment tgt value
147148
148−parseManyStatements :: P.Parsec String () [Statement]
149+parseManyStatements :: I.IndentParser String () [Statement]
149150parseManyStatements = C.braces $ P.many (parseStatement True)
150151
151−parseWhile :: P.Parsec String () Statement
152+parseWhile :: I.IndentParser String () Statement
152153parseWhile = While <$> (C.reserved "while" *> C.parens parseValue)
153154 <*> parseManyStatements
154155
155−parseFor :: P.Parsec String () Statement
156+parseFor :: I.IndentParser String () Statement
156157parseFor = For <$> (C.reserved "for" *> C.parens forIntro)
157158 <*> parseManyStatements
158159 where
@@ -160,16 +161,16 @@ parseFor = For <$> (C.reserved "for" *> C.parens forIntro)
160161 <*> (C.semi *> parseValue)
161162 <*> (C.semi *> parseStatement False)
162163
163−parseIfThenElse :: P.Parsec String () Statement
164+parseIfThenElse :: I.IndentParser String () Statement
164165parseIfThenElse = IfThenElse
165166 <$> (C.reserved "if" *> C.parens parseValue)
166167 <*> parseManyStatements
167168 <*> P.optionMaybe (C.reserved "else" *> parseManyStatements)
168169
169−parseReturn :: Bool -> P.Parsec String () Statement
170+parseReturn :: Bool -> I.IndentParser String () Statement
170171parseReturn requireSemi = Return <$> (C.reserved "return" *> parseValue <* when requireSemi (void C.semi))
171172
172−parseStatement :: Bool -> P.Parsec String () Statement
173+parseStatement :: Bool -> I.IndentParser String () Statement
173174parseStatement requireSemi = P.choice $ map P.try
174175 [ parseVariableIntroduction requireSemi
175176 , parseAssignment requireSemi
@@ -178,38 +179,38 @@ parseStatement requireSemi = P.choice $ map P.try
178179 , parseIfThenElse
179180 , parseReturn requireSemi ]
180181
181−parseStringBinder :: P.Parsec String () Binder
182+parseStringBinder :: I.IndentParser String () Binder
182183parseStringBinder = StringBinder <$> C.stringLiteral
183184
184−parseBooleanBinder :: P.Parsec String () Binder
185+parseBooleanBinder :: I.IndentParser String () Binder
185186parseBooleanBinder = BooleanBinder <$> booleanLiteral
186187
187−parseNumberBinder :: P.Parsec String () Binder
188+parseNumberBinder :: I.IndentParser String () Binder
188189parseNumberBinder = NumberBinder <$> C.naturalOrFloat
189190
190−parseVarBinder :: P.Parsec String () Binder
191+parseVarBinder :: I.IndentParser String () Binder
191192parseVarBinder = VarBinder <$> C.parseIdent
192193
193−parseNullaryBinder :: P.Parsec String () Binder
194+parseNullaryBinder :: I.IndentParser String () Binder
194195parseNullaryBinder = NullaryBinder <$> C.lexeme C.properName
195196
196−parseUnaryBinder :: P.Parsec String () Binder
197+parseUnaryBinder :: I.IndentParser String () Binder
197198parseUnaryBinder = UnaryBinder <$> C.lexeme C.properName <*> parseBinder
198199
199−parseObjectBinder :: P.Parsec String () Binder
200+parseObjectBinder :: I.IndentParser String () Binder
200201parseObjectBinder = ObjectBinder <$> C.braces (C.commaSep parseIdentifierAndBinder)
201202
202−parseArrayBinder :: P.Parsec String () Binder
203+parseArrayBinder :: I.IndentParser String () Binder
203204parseArrayBinder = C.squares $ ArrayBinder <$> (C.commaSep parseBinder) <*> P.optionMaybe (C.colon *> parseBinder)
204205
205−parseIdentifierAndBinder :: P.Parsec String () (String, Binder)
206+parseIdentifierAndBinder :: I.IndentParser String () (String, Binder)
206207parseIdentifierAndBinder = do
207208 name <- C.lexeme C.identifier
208209 C.lexeme $ P.char '='
209210 binder <- parseBinder
210211 return (name, binder)
211212
212−parseBinder :: P.Parsec String () Binder
213+parseBinder :: I.IndentParser String () Binder
213214parseBinder = P.choice $ map P.try
214215 [ parseStringBinder
215216 , parseBooleanBinder
@@ -221,7 +222,7 @@ parseBinder = P.choice $ map P.try
221222 , parseArrayBinder
222223 , C.parens parseBinder ]
223224
224−parseAssignmentTarget :: P.Parsec String () AssignmentTarget
225+parseAssignmentTarget :: I.IndentParser String () AssignmentTarget
225226parseAssignmentTarget = buildExpressionParser operators (AssignVariable <$> C.parseIdent)
226227 where
227228 operators = [ [ Postfix $ AssignArrayIndex <$> C.squares parseValue