packages feed

purescript-cst 0.4.0.0 → 0.5.0.0

raw patch · 6 files changed

+170/−20 lines, 6 filesdep ~basedep ~containersdep ~dlist

Dependency ranges changed: base, containers, dlist, microlens, scientific, semigroups, serialise, vector

Files

README.md view
@@ -11,6 +11,9 @@ | 0.14.2 | 0.2.0.0 | | 0.14.3 | 0.3.0.0 | | 0.14.4 | 0.4.0.0 |+| 0.14.5 | 0.4.0.0 |+| 0.14.6 | 0.4.0.0 |+| 0.14.7 | 0.5.0.0 |  Before v0.14.2, there was a third package, `purescript-ast`. In v0.14.2, `purescript-ast` was merged into `purescript-cst`. 
purescript-cst.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               purescript-cst-version:            0.4.0.0+version:            0.5.0.0 license:            BSD-3-Clause license-file:       LICENSE copyright:@@ -83,18 +83,18 @@     build-depends:         aeson >=1.5.6.0 && <1.6,         array >=0.5.4.0 && <0.6,-        base >=4.14.1.0 && <4.15,+        base >=4.14.3.0 && <4.15,         base-compat >=0.11.2 && <0.12,         bytestring >=0.10.12.0 && <0.11,-        containers >=0.6.2.1 && <0.7,+        containers >=0.6.5.1 && <0.7,         deepseq >=1.4.4.0 && <1.5,-        dlist >=0.8.0.8 && <0.9,+        dlist ==1.0.*,         filepath >=1.4.2.1 && <1.5,-        microlens >=0.4.11.2 && <0.5,+        microlens >=0.4.12.0 && <0.5,         mtl >=2.2.2 && <2.3,         protolude >=0.3.0 && <0.4,-        scientific >=0.3.6.2 && <0.4,-        semigroups >=0.19.1 && <0.20,+        scientific >=0.3.7.0 && <0.4,+        semigroups >=0.19.2 && <0.20,+        serialise >=0.2.4.0 && <0.3,         text >=1.2.4.1 && <1.3,-        serialise >=0.2.3.0 && <0.3,-        vector >=0.12.1.2 && <0.13+        vector >=0.12.3.1 && <0.13
src/Language/PureScript/AST/Declarations.hs view
@@ -97,6 +97,7 @@   | CheckHint   | PositionHint   | SolverHint+  | DeclarationHint   | OtherHint   deriving (Show, Eq) @@ -504,13 +505,13 @@ declName (FixityDeclaration _ (Right (TypeFixity _ _ n))) = Just (TyOpName n) declName (TypeClassDeclaration _ n _ _ _ _) = Just (TyClassName n) declName (TypeInstanceDeclaration _ _ _ n _ _ _ _) = IdentName <$> hush n+declName (RoleDeclaration RoleDeclarationData{..}) = Just (TyName rdeclIdent) declName ImportDeclaration{} = Nothing declName BindingGroupDeclaration{} = Nothing declName DataBindingGroupDeclaration{} = Nothing declName BoundValueDeclaration{} = Nothing declName KindDeclaration{} = Nothing declName TypeDeclaration{} = Nothing-declName RoleDeclaration{} = Nothing  -- | -- Test if a declaration is a value declaration
src/Language/PureScript/CST/Layout.hs view
@@ -1,4 +1,11 @@--- | The parser itself is unaware of indentation, and instead only parses explicit+-- |+-- ## High-Level Summary+--+-- This section provides a high-level summary of this file. For those who+-- know more about compiler-development, the below explanation is likely enough.+-- For everyone else, see the next section.+--+-- The parser itself is unaware of indentation, and instead only parses explicit -- delimiters which are inserted by this layout algorithm (much like Haskell). -- This is convenient because the actual grammar can be specified apart from the -- indentation rules. Haskell has a few problematic productions which make it@@ -17,7 +24,148 @@ -- such an algorithm. Unquoted properties for layout keywords introduce a domino -- effect of complexity since we have to mask and unmask any usage of . (also in -- foralls!) or labels in record literals.-+--+-- ## Detailed Summary+--+-- ### The Problem+--+-- The parser itself is unaware of indentation or other such layout concerns.+-- Rather than dealing with it explicitly, the parser and its+-- grammar rules are only aware of normal tokens (e.g. @TokLowerName@) and+-- three special zero-width tokens, @TokLayoutStart@, @TokLayoutSep@,+-- and @TokLayoutEnd@. This is convenient because the actual grammar+-- can be specified apart from the indentation rules and other such+-- layout concerns.+--+-- For a simple example, the parser parses all three examples of the code below+-- using the exact same grammar rules for the @let@ keyword despite+-- each example using different indentations levels:+--+-- @+-- -- Example 1+-- let foo = 5+--     x = 2 in foo+--+-- -- Example 2+-- let+--   bar = 5+--   y = 2+-- in bar+--+-- -- Example 3+-- let        baz+--                  =+--              5+--            z= 2 in baz+-- @+--+-- Each block of code might appear to the parser as a stream of the+-- following source tokens where the @\{@ sequence represents+-- @TokLayoutStart@, the @\;@ sequence represents @TokLayoutSep@,+-- and the @\}@ sequence represents @TokLayoutEnd@:+-- - @let \{foo = 5\;x = 2\} in foo@+-- - @let \{bar = 5\;y = 2\} in bar@+-- - @let \{baz = 5\;z = 2\} in baz@+--+--+-- For a more complex example, consider commas:+--+-- @+-- case one, { twoA, twoB }, [ three1+--    , three2+--    ,   do+--      { three3, three4 } <- case arg1, arg2 of+--         Nothing, _ -> { three3: 1, three4: 2 }+--         Just _, Nothing -> { three3: 2, three4: 3 }+--         _, _ -> { three3: 3, three4: 4 }+--      pure $ three3 + three4+--    ] of+-- @+--+-- Which of the above 13 commas function as the separaters between the+-- case binders (e.g. @one@) in the outermost @case ... of@ context?+--+-- ### The Solution+--+-- The parser doesn't have to care about layout concerns (e.g. indentation+-- or what starts and ends a context, such as a case binder) because the+-- lexer solves that problem instead.+--+-- So, how does the lexer solve this problem? It follows this general algorithm:+-- 1. Lex the source code text into an initial stream of `SourceToken`s+--    that do not have any of the three special tokens mentioned previously.+-- 2. On a token-by-token basis, determine whether the lexer should+--        1. insert one of the three special tokens,+--        2. modify the current context (e.g. are we within a case binder?+--           Are we in a record expression?)+--+-- Step 2 is handled via 'insertLayout' and is essentially a state machine.+-- The layout delimiters, (e.g. 'LytCase', 'LytBrace', 'LytProperty',+-- and 'LytOf' in the next section's example) either stop certain "rules"+-- from applying or ensure that certain "rules" now apply. By "rules",+-- we mean whether and where one of the three special tokens are added.+-- The comments in the source code for the 'insertLayout' algorithm call+-- pushing these delimiters onto the stack "masking" and popping them off+-- as "unmasking". Seeing when a layout delimiter is pushed and popped+-- are the keys to understanding this algorithm.+--+-- ### Walking Through an Example+--+-- Before showing an example, let's remember a few things.+--   1. The @TokLowerName "case"@ token (i.e. a "case" keyword) indicates the start+--      of a @case ... of@ context. That context includes case binders (like the+--      example shown previously) that can get quite complex. When encountered,+--      we may need to insert one or more of the three special tokens here+--      until we encounter the terminating @TokLowerName "of"@ token that+--      signifies its end.+--   2. "case" and "of" can also appear as a record field's name. In such a context,+--      they would not start or end a @case ... of@ block.+--+-- Given the below source code...+--+-- @+-- case { case: "foo", of: "bar" } of+-- @+--+-- the lexer would go through something like the following states:+-- 1. Encountered @TokLowerName "case"@. Update current context to+--    "within a case of expression" by pushing the 'LytCase' delimiter+--    onto the layout delimiter stack. Insert the @case@ token+--    into the stream of source tokens.+-- 2. Encountered @TokLeftBrace@. Update current context to+--    "within a record expression" by pushing the 'LytBrace' delimiter.+--    Since we expect a field name to be the next token we see,+--    which may include a reserved keyword, update the current context again to+--    "expecting a field name" by pushing the `LytProperty`.+--    delimiter. Insert the @{@ token into the stream of source tokens.+-- 3. Encountered @TokLowerName "case"@. Check the current context.+--    Since it's a `LytProperty`, this is a field name and we shouldn't+--    assume that the next few tokens will be case binders. However,+--    since this might be a record with no more fields, update the+--    current context back to "within a record expression" by popping+--    the `LytProperty` off the layout delimiter stack. Insert the @case@ token+-- 4. Encountered @TokColon@. Insert the @:@ token+-- 5. Encountered @TokLowerName "foo"@. Insert the @foo@ token.+-- 6. Encountered @TokComma@. Check the current context. Since it's a `LytBrace`,+--    we're in a record expression and there is another field. Update the+--    current context by pushing `LytProperty` as we expect a field name again.+-- 7. Encountered @TokLowerName "of"@. Check the current context.+--    Since it's a `LytProperty`, this is a field name rather+--    than the end of a case binder. Thus, we don't expect the next tokens+--    to be the @body@ in a @case ... of body@ expression. However, since+--    this might be a record with no more fields, update the current context+--    back to "within a record expression" by popping the `LytProperty`+--    off the stack. Insert the @of@ token.+-- 8. Encountered @TokRightBrace@. Check the current context.+--    Since it's a `LytBrace`, this is the end of a record expression.+--    Update the current context to "within a case of expression"+--    by popping the `LytBrace` off the stack. Insert the @}@ token.+-- 9. Encountered @TokLowername "of"@. Check the current context.+--    Since it's a 'LytCase', this is the end of a @case ... of@ expression+--    and the body will follow. Update the current context to+--    "body of a case of expression" by pushing 'LytOf' onto the layout stack.+--    Insert the @of@ token into the stream of tokens.+-- module Language.PureScript.CST.Layout where  import Prelude
src/Language/PureScript/Environment.hs view
@@ -35,11 +35,6 @@   , dataConstructors :: M.Map (Qualified (ProperName 'ConstructorName)) (DataDeclType, ProperName 'TypeName, SourceType, [Ident])   -- ^ Data constructors currently in scope, along with their associated type   -- constructor name, argument types and return type.-  , roleDeclarations :: M.Map (Qualified (ProperName 'TypeName)) [Role]-  -- ^ Explicit role declarations currently in scope. Note that this field is-  -- only used to store declared roles temporarily until they can be checked;-  -- to find a type's real checked and/or inferred roles, refer to the TypeKind-  -- in the `types` field.   , typeSynonyms :: M.Map (Qualified (ProperName 'TypeName)) ([(Text, Maybe SourceType)], SourceType)   -- ^ Type synonyms currently in scope   , typeClassDictionaries :: M.Map (Maybe ModuleName) (M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) (NEL.NonEmpty NamedDict)))@@ -103,7 +98,7 @@  -- | The initial environment with no values and only the default javascript types defined initEnvironment :: Environment-initEnvironment = Environment M.empty allPrimTypes M.empty M.empty M.empty M.empty allPrimClasses+initEnvironment = Environment M.empty allPrimTypes M.empty M.empty M.empty allPrimClasses  -- | A constructor for TypeClassData that computes which type class arguments are fully determined -- and argument covering sets.@@ -434,7 +429,7 @@     , (primSubName C.typeError "Fail", (kindDoc -:> kindConstraint, ExternData [Nominal]))     , (primSubName C.typeError "Warn", (kindDoc -:> kindConstraint, ExternData [Nominal]))     , (primSubName C.typeError "Text", (kindSymbol -:> kindDoc, ExternData [Phantom]))-    , (primSubName C.typeError "Quote", (kindType -:> kindDoc, ExternData [Phantom]))+    , (primSubName C.typeError "Quote", (tyForall "k" kindType $ tyVar "k" -:> kindDoc, ExternData [Phantom]))     , (primSubName C.typeError "QuoteLabel", (kindSymbol -:> kindDoc, ExternData [Phantom]))     , (primSubName C.typeError "Beside", (kindDoc -:> kindDoc -:> kindDoc, ExternData [Phantom, Phantom]))     , (primSubName C.typeError "Above", (kindDoc -:> kindDoc -:> kindDoc, ExternData [Phantom, Phantom]))
src/Language/PureScript/Names.hs view
@@ -78,11 +78,14 @@ instance NFData Ident instance Serialise Ident +unusedIdent :: Text+unusedIdent = "$__unused"+ runIdent :: Ident -> Text runIdent (Ident i) = i runIdent (GenIdent Nothing n) = "$" <> T.pack (show n) runIdent (GenIdent (Just name) n) = "$" <> name <> T.pack (show n)-runIdent UnusedIdent = "$__unused"+runIdent UnusedIdent = unusedIdent  showIdent :: Ident -> Text showIdent = runIdent