on master help sign in
Parse more liberally, give errors in validation phase for better messages
commitd163289f5d6264c0433bfbe09ddd7466fcf049a2 authorEvan Czaplicki <info@elm-lang.org> dateMon 8 Feb 2016, 18:12 (11 years ago) parent8d8afda
12 files changed+210−114
src/AST/Module.hs+32−14 src/Canonicalize.hs+1−1 src/Canonicalize/Setup.hs+2−2 src/Elm/Compiler.hs+2−2 src/Generate/JavaScript.hs+1−1 src/Nitpick/PatternMatches.hs+1−1 src/Optimize.hs+2−2 src/Parse/Module.hs+47−55 src/Parse/Parse.hs+3−34 src/Reporting/Error/Syntax.hs+5 src/Type/Inference.hs+1−1 src/Validate.hs+113−1
src/AST/Module.hs+32−14
@@ -1,8 +1,8 @@
11module AST.Module
2− ( Header(..), Module(..), Tag(..)
2+ ( Header(..), Module(..)
33
4− , Source, SourceInfo(..)
5− , Valid, ValidInfo(..)
4+ , Source, SourceInfo(..), SourceTag(..), SourceSettings, emptySettings
5+ , Valid, ValidInfo(..), ValidEffects(..)
66 , Canonical, Optimized, Info(..)
77
88 , UserImport, DefaultImport, ImportMethod(..)
@@ -38,10 +38,11 @@ import qualified Reporting.Region as R
3838{-| Basic info needed to identify modules and determine dependencies. -}
3939data Header imports =
4040 Header
41− { _tag :: Tag
41+ { _tag :: SourceTag
4242 , _name :: Name.Raw
43− , _docs :: A.Located (Maybe String)
4443 , _exports :: Var.Listing (A.Located Var.Value)
44+ , _settings :: SourceSettings
45+ , _docs :: A.Located (Maybe String)
4546 , _imports :: imports
4647 }
4748
@@ -52,32 +53,42 @@ data Header imports =
5253
5354data Module phase =
5455 Module
55− { tag :: Tag
56− , name :: Name.Canonical
56+ { name :: Name.Canonical
5757 , path :: FilePath
5858 , info :: phase
5959 }
6060
6161
62−data Tag
63− = Normal
64− | Effect (Maybe (A.Located String)) (Maybe (A.Located String))
65− | Foreign R.Region
66−
67−
6862type Source =
6963 Module SourceInfo
7064
7165
7266data SourceInfo =
7367 Source
74− { srcDocs :: A.Located (Maybe String)
68+ { srcTag :: SourceTag
69+ , srcSettings :: SourceSettings
70+ , srcDocs :: A.Located (Maybe String)
7571 , srcExports :: Var.Listing (A.Located Var.Value)
7672 , srcImports :: [UserImport]
7773 , srcDecls :: [Decl.Source]
7874 }
7975
8076
77+data SourceTag
78+ = SrcNormal
79+ | SrcEffect
80+ | SrcForeign
81+
82+
83+type SourceSettings =
84+ A.Located [(A.Located String, A.Located String)]
85+
86+
87+emptySettings :: SourceSettings
88+emptySettings =
89+ A.A (error "region of empty settings should not be needed") []
90+
91+
8192type Valid =
8293 Module ValidInfo
8394
@@ -88,9 +99,16 @@ data ValidInfo =
8899 , validExports :: Var.Listing (A.Located Var.Value)
89100 , validImports :: ([DefaultImport], [UserImport])
90101 , validDecls :: [Decl.Valid]
102+ , validEffects :: ValidEffects
91103 }
92104
93105
106+data ValidEffects
107+ = ValidNormal
108+ | ValidEffect (Maybe (A.Located String)) (Maybe (A.Located String))
109+ | ValidForeign
110+
111+
94112type Canonical =
95113 Module (Info Canonical.Expr)
96114
src/Canonicalize.hs+1−1
@@ -46,7 +46,7 @@ module'
4646 -> R.Result Warning.Warning Error.Error Module.Canonical
4747module' canonicalImports interfaces modul =
4848 let
49− (Module.Valid docs exports imports decls) =
49+ (Module.Valid docs exports imports decls effects) =
5050 Module.info modul
5151
5252 importDict =
src/Canonicalize/Setup.hs+2−2
@@ -30,9 +30,9 @@ environment
3030 -> Module.Interfaces
3131 -> Module.Valid
3232 -> Result.ResultErr Env.Environment
33−environment importDict interfaces (Module.Module _ name _ info) =
33+environment importDict interfaces (Module.Module name _ info) =
3434 let
35− (Module.Valid _ _ (defaults, imports) decls) =
35+ (Module.Valid _ _ (defaults, imports) decls effects) =
3636 info
3737
3838 allImports =
src/Elm/Compiler.hs+2−2
@@ -53,7 +53,7 @@ parseDependencies sourceCode =
5353 Result.Err msgs ->
5454 Left $ map (Error . A.map Error.Syntax) msgs
5555
56− Result.Ok (Module.Header _kind name _docs _exports imports) ->
56+ Result.Ok (Module.Header _ name _ _ _ imports) ->
5757 Right
5858 ( PublicModule.Name name
5959 , map (PublicModule.Name . fst . A.drop) imports
@@ -107,7 +107,7 @@ docsGen
107107 :: Bool
108108 -> Module.Optimized
109109 -> Result.Result w Error.Error (Maybe Docs.Documentation)
110−docsGen isExposed (Module.Module _ name _ info) =
110+docsGen isExposed (Module.Module name _ info) =
111111 if not isExposed then
112112 Result.ok Nothing
113113
src/Generate/JavaScript.hs+1−1
@@ -17,7 +17,7 @@ import qualified Generate.JavaScript.Variable as Var
1717
1818
1919generate :: Module.Optimized -> String
20−generate (Module.Module _ (ModuleName.Canonical _ name) _ info) =
20+generate (Module.Module (ModuleName.Canonical _ name) _ info) =
2121 let
2222 body =
2323 concat
src/Nitpick/PatternMatches.hs+1−1
@@ -27,7 +27,7 @@ patternMatches
2727 :: Module.Interfaces
2828 -> Module.Canonical
2929 -> Result.Result w Error.Error DT.VariantDict
30−patternMatches interfaces (Module.Module _ name _ info) =
30+patternMatches interfaces (Module.Module name _ info) =
3131 let
3232 tagDict =
3333 toTagDict interfaces name (Module.unions info)
src/Optimize.hs+2−2
@@ -24,7 +24,7 @@ import qualified Reporting.Region as R
2424
2525
2626optimize :: DT.VariantDict -> Module.Canonical -> Module.Optimized
27−optimize variantDict module_@(Module.Module _ home _ info) =
27+optimize variantDict modul@(Module.Module home _ info) =
2828 let
2929 (defs, _) =
3030 flattenLets [] (Module.program info)
@@ -35,7 +35,7 @@ optimize variantDict module_@(Module.Module _ home _ info) =
3535 optInfo =
3636 info { Module.program = optDefs }
3737 in
38− module_ { Module.info = optInfo }
38+ modul { Module.info = optInfo }
3939
4040
4141flattenLets :: [Can.Def] -> Can.Expr -> ([Can.Def], Can.Expr)
src/Parse/Module.hs+47−55
@@ -8,7 +8,6 @@ import qualified AST.Module as Module
88import qualified AST.Module.Name as ModuleName
99import qualified AST.Variable as Var
1010import qualified Reporting.Annotation as A
11−import qualified Reporting.Region as R
1211
1312
1413getModuleName :: String -> Maybe String
@@ -16,7 +15,7 @@ getModuleName source =
1615 let
1716 minimalParser =
1817 do optional freshLine
19− (_, names, _) <- moduleDecl
18+ (ModuleDecl _ names _ _) <- moduleDecl
2019 return (ModuleName.toString names)
2120 in
2221 case iParse minimalParser source of
@@ -30,9 +29,9 @@ getModuleName source =
3029header :: IParser (Module.Header [Module.UserImport])
3130header =
3231 do optional freshLine
33− (tag, names, exports) <-
32+ (ModuleDecl tag names exports settings) <-
3433 option
35− (Module.Normal, ["Main"], Var.openListing)
34+ (ModuleDecl Module.SrcNormal ["Main"] Var.openListing Module.emptySettings)
3635 (moduleDecl `followedBy` freshLine)
3736
3837 docs <-
@@ -43,70 +42,63 @@ header =
4342
4443 imports' <- imports
4544
46− return (Module.Header tag names docs exports imports')
45+ return (Module.Header tag names exports settings docs imports')
4746
4847
49−moduleDecl :: IParser (Module.Tag, [String], Var.Listing (A.Located Var.Value))
48+data ModuleDecl =
49+ ModuleDecl
50+ { _tag :: Module.SourceTag
51+ , _name :: [String]
52+ , _exports :: Var.Listing (A.Located Var.Value)
53+ , _settings :: Module.SourceSettings
54+ }
55+
56+
57+moduleDecl :: IParser ModuleDecl
5058moduleDecl =
5159 expecting "a module declaration" $
5260 do
53− endParser <-
54− choice
55− [
56− do try (reserved "module")
57− return (return Module.Normal)
58− ,
59− do try (reserved "effect")
60− whitespace
61− reserved "module"
62− return parseEffects
63− ,
64− do start <- getMyPosition
65− reserved "foreign"
66− whitespace
67− reserved "effect"
68− whitespace
69− reserved "module"
70− end <- getMyPosition
71− return (return (Module.Foreign (R.Region start end)))
72− ]
61+ tag <- parseTag
7362
74− whitespace
75− names <- dotSep1 capVar <?> "the name of this module"
63+ names <- padded (dotSep1 capVar) <?> "the name of this module"
7664
77− padded (reserved "exposing")
65+ settings <- option Module.emptySettings parseSetting
7866
79− exports <- listing (addLocation value)
67+ exports <- padded (listing (addLocation value))
8068
81− tag <- endParser
69+ reserved "where"
8270
83− return (tag, names, exports)
71+ return (ModuleDecl tag names exports settings)
8472
8573
86−parseEffects :: IParser Module.Tag
87−parseEffects =
88− do padded (reserved "where")
89− brackets $ choice $
90− [ do cmd <- entry "command"
91− whitespace
92− sub <- option Nothing (secondEntry "subscription")
93− return (Module.Effect cmd sub)
94− , do sub <- entry "subscription"
95− whitespace
96− cmd <- option Nothing (secondEntry "command")
97− return (Module.Effect cmd sub)
98− ]
99− where
100− entry name =
101− do try (string name)
102− padded equals
103− typeName <- addLocation capVar
104− return (Just typeName)
105−
106− secondEntry name =
107− do try comma
74+parseTag :: IParser Module.SourceTag
75+parseTag =
76+ choice
77+ [
78+ do try (reserved "module")
79+ return Module.SrcNormal
80+ ,
81+ do try (reserved "effect")
82+ whitespace
83+ reserved "module"
84+ return Module.SrcEffect
85+ ,
86+ do reserved "foreign"
87+ whitespace
88+ reserved "effect"
10889 whitespace
109− entry name
90+ reserved "module"
91+ return Module.SrcForeign
92+ ]
93+
94+
95+parseSetting :: IParser Module.SourceSettings
96+parseSetting =
97+ addLocation $ brackets $ commaSep $
98+ do name <- addLocation lowVar
99+ padded equals
100+ typeName <- addLocation capVar
101+ return (name, typeName)
110102
111103
112104imports :: IParser [Module.UserImport]
src/Parse/Parse.hs+3−34
@@ -9,7 +9,6 @@ import qualified Text.Parsec.Error as Parsec
99import qualified AST.Declaration as Decl
1010import qualified AST.Module as Module
1111import qualified AST.Module.Name as ModuleName
12−import qualified Elm.Compiler.Imports as Imports
1312import qualified Elm.Package as Package
1413import Parse.Helpers
1514import qualified Parse.Module as Parse (header)
@@ -30,36 +29,7 @@ program pkgName table src =
3029 do modul <-
3130 parseWithTable table src (programParser pkgName)
3231
33− let
34− (Module.Source docs exports imports sourceDecls) =
35− Module.info modul
36−
37− validDecls <-
38− Validate.declarations sourceDecls
39−
40− return $
41− modul
42− { Module.info =
43− Module.Valid
44− docs
45− exports
46− (addDefaults pkgName imports)
47− validDecls
48− }
49−
50−
51−-- determine if default imports should be added, only elm-lang/core is exempt
52−addDefaults
53− :: Package.Name
54− -> [Module.UserImport]
55− -> ([Module.DefaultImport], [Module.UserImport])
56−addDefaults pkgName imports =
57− flip (,) imports $
58− if pkgName == Package.coreName then
59− []
60−
61− else
62− Imports.defaults
32+ Validate.module' modul
6333
6434
6535
@@ -68,7 +38,7 @@ addDefaults pkgName imports =
6838
6939programParser :: Package.Name -> IParser Module.Source
7040programParser pkgName =
71− do (Module.Header tag name docs exports imports) <-
41+ do (Module.Header tag name exports settings docs imports) <-
7242 Parse.header
7343
7444 decls <-
@@ -80,10 +50,9 @@ programParser pkgName =
8050
8151 return $
8252 Module.Module
83− tag
8453 (ModuleName.Canonical pkgName name)
8554 ""
86− (Module.Source docs exports imports decls)
55+ (Module.Source tag settings docs exports imports decls)
8756
8857
8958declarations :: IParser [Decl.Source]
src/Reporting/Error/Syntax.hs+5
@@ -20,6 +20,11 @@ data Error
2020 | CommentOnComment
2121 | CommentOnNothing
2222
23+ | SettingsOnNormalModule
24+ | SettingsOnForeignModule
25+ | DuplicateSettingOnEffectModule String
26+ | BadSettingOnEffectModule String
27+
2328 | InfixDuplicate String
2429 | TypeWithoutDefinition String
2530 | DuplicateFieldName String
src/Type/Inference.hs+1−1
@@ -81,7 +81,7 @@ canonicalizeValues env (moduleName, iface) =
8181
8282
8383canonicalizeUnions :: Module.Interfaces -> Module.Canonical -> [Module.CanonicalUnion]
84−canonicalizeUnions interfaces (Module.Module _ name _ info) =
84+canonicalizeUnions interfaces (Module.Module name _ info) =
8585 localUnions ++ importedUnions
8686 where
8787 localUnions :: [Module.CanonicalUnion]
src/Validate.hs+113−1
@@ -1,5 +1,5 @@
11{-# OPTIONS_GHC -Wall #-}
2−module Validate (declarations) where
2+module Validate (module') where
33
44import Control.Monad (foldM)
55import qualified Data.Map as Map
@@ -11,8 +11,12 @@ import AST.Expression.General as Expr
1111import qualified AST.Expression.Source as Source
1212import qualified AST.Expression.Valid as Valid
1313import qualified AST.Declaration as D
14+import qualified AST.Module as Module
15+import qualified AST.Module.Name as ModuleName
1416import qualified AST.Pattern as Pattern
1517import qualified AST.Type as Type
18+import qualified Elm.Compiler.Imports as Imports
19+import qualified Elm.Package as Package
1620import Elm.Utils ((|>))
1721import qualified Reporting.Annotation as A
1822import qualified Reporting.Error.Syntax as Error
@@ -21,6 +25,114 @@ import qualified Reporting.Result as Result
2125
2226
2327
28+-- MODULES
29+
30+
31+module' :: Module.Source -> Result.Result wrn Error.Error Module.Valid
32+module' (Module.Module name path info) =
33+ let
34+ (ModuleName.Canonical pkgName _) =
35+ name
36+
37+ (Module.Source tag settings docs exports imports decls) =
38+ info
39+ in
40+ do validEffects <- validateModuleDecl tag settings
41+ validDecls <- declarations decls
42+
43+ return $ Module.Module name path $
44+ Module.Valid docs exports (addDefaults pkgName imports) validDecls validEffects
45+
46+
47+-- determine if default imports should be added, only elm-lang/core is exempt
48+addDefaults
49+ :: Package.Name
50+ -> [Module.UserImport]
51+ -> ([Module.DefaultImport], [Module.UserImport])
52+addDefaults pkgName imports =
53+ flip (,) imports $
54+ if pkgName == Package.coreName then
55+ []
56+
57+ else
58+ Imports.defaults
59+
60+
61+validateModuleDecl
62+ :: Module.SourceTag
63+ -> Module.SourceSettings
64+ -> Result.Result wrn Error.Error Module.ValidEffects
65+validateModuleDecl tag settings =
66+ case tag of
67+ Module.SrcNormal ->
68+ do noSettings Error.SettingsOnNormalModule settings
69+ return Module.ValidNormal
70+
71+ Module.SrcForeign ->
72+ do noSettings Error.SettingsOnForeignModule settings
73+ return Module.ValidForeign
74+
75+ Module.SrcEffect ->
76+ gatherEffectSettings settings
77+
78+
79+noSettings
80+ :: Error.Error
81+ -> Module.SourceSettings
82+ -> Result.Result wrn Error.Error ()
83+noSettings errorMsg (A.A region settings) =
84+ case settings of
85+ [] ->
86+ Result.ok ()
87+
88+ _ : _ ->
89+ Result.throw region errorMsg
90+
91+
92+gatherEffectSettings
93+ :: Module.SourceSettings
94+ -> Result.Result wrn Error.Error Module.ValidEffects
95+gatherEffectSettings (A.A _ pairs) =
96+ uncurry Module.ValidEffect <$>
97+ gatherEffectSettingsHelp (Nothing, Nothing) pairs
98+
99+
100+type Effects =
101+ (Maybe (A.Located String), Maybe (A.Located String))
102+
103+
104+gatherEffectSettingsHelp
105+ :: Effects
106+ -> [(A.Located String, A.Located String)]
107+ -> Result.Result wrn Error.Error Effects
108+gatherEffectSettingsHelp effects@(maybeCmd, maybeSub) pairs =
109+ case pairs of
110+ [] ->
111+ Result.ok effects
112+
113+ (A.A region name, effect) : rest ->
114+ case name of
115+ "command" ->
116+ case maybeCmd of
117+ Nothing ->
118+ gatherEffectSettingsHelp (Just effect, maybeSub) rest
119+
120+ Just _ ->
121+ Result.throw region (Error.DuplicateSettingOnEffectModule name)
122+
123+ "subscription" ->
124+ case maybeSub of
125+ Nothing ->
126+ gatherEffectSettingsHelp (maybeCmd, Just effect) rest
127+
128+ Just _ ->
129+ Result.throw region (Error.DuplicateSettingOnEffectModule name)
130+
131+ _ ->
132+ Result.throw region (Error.BadSettingOnEffectModule name)
133+
134+
135+
24136-- COLLAPSE COMMENTS
25137
26138