1
1
mirror of https://github.com/github/semantic.git synced 2024-12-01 09:15:01 +03:00

Add a lot of comments and some clarifying patterns.

This commit is contained in:
Patrick Thomson 2019-09-27 17:36:08 -04:00
parent b1611e13e8
commit 825726d37e

View File

@ -1,7 +1,7 @@
{-# LANGUAGE ConstraintKinds, DataKinds, DefaultSignatures, DeriveAnyClass, DeriveGeneric, DerivingStrategies,
DerivingVia, DisambiguateRecordFields, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving,
LambdaCase, NamedFieldPuns, OverloadedLists, OverloadedStrings, ScopedTypeVariables, StandaloneDeriving,
TypeApplications, TypeOperators, UndecidableInstances, ViewPatterns #-}
LambdaCase, NamedFieldPuns, OverloadedLists, OverloadedStrings, PatternSynonyms, ScopedTypeVariables,
StandaloneDeriving, TypeApplications, TypeOperators, UndecidableInstances, ViewPatterns #-}
module Language.Python.Core
( compile
@ -14,11 +14,12 @@ import Prelude hiding (fail)
import Control.Effect hiding ((:+:))
import Control.Effect.Reader
import Control.Monad.Fail
import Data.Bifunctor
import Data.Coerce
import Data.Core as Core
import Data.Foldable
import Data.List (mapAccumL, mapAccumR)
import Data.List.NonEmpty(NonEmpty (..))
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.Loc
import Data.Name as Name
import Data.Stack (Stack)
@ -32,6 +33,7 @@ import qualified TreeSitter.Python.AST as Py
import TreeSitter.Span (Span)
import qualified TreeSitter.Span as TreeSitter
-- Access to the current filename as Text to stick into location annotations.
newtype SourcePath = SourcePath { rawPath :: Text }
deriving stock (Eq, Show)
deriving newtype IsString
@ -46,6 +48,17 @@ newtype Bindings = Bindings { unBindings :: Stack Name }
def :: Name -> Bindings -> Bindings
def n = coerce (Stack.:> n)
-- Useful pattern synonym for extracting a single identifier from
-- a Python ExpressionList. Easier than pattern-matching every time.
-- TODO: when this is finished, we won't need this pattern, as we'll
-- handle ExpressionLists the smart way every time.
pattern OneExpression :: Name -> Py.ExpressionList a
pattern OneExpression name <- Py.ExpressionList
{ Py.extraChildren =
[ Py.PrimaryExpressionExpression (Py.IdentifierPrimaryExpression (Py.Identifier { bytes = name }))
]
}
-- We leave the representation of Core syntax abstract so that it's not
-- possible for us to 'cheat' by pattern-matching on or eliminating a
-- compiled term.
@ -111,32 +124,35 @@ deriving via CompileSum (Either l r) instance (Compile l, Compile r) => Compile
instance Compile (Py.AssertStatement Span)
instance Compile (Py.Attribute Span)
type RHS a = Either (Py.Assignment a) (Either (Py.AugmentedAssignment a) (Either (Py.ExpressionList a) (Py.Yield a)))
type Desugared a = Either (Py.ExpressionList a) (Py.Yield a)
-- Assignment compilation. Assignments are an uneasy hybrid of expressions
-- (since they appear to have values, i.e. `a = b = c`) and statements (because
-- they introduce bindings. For that reason, they deserve special attention.
--
-- The correct desugaring for the expression above looks like, given a continuation @cc@:
-- @
-- (b :<- c) >>>= (a :<- b) >>>= cont
-- @
-- The tree structure that we get out of tree-sitter is not particulary conducive to expressing
-- this naturally, so we engage in a small desugaring step so that we can turn a list [a, b, c]
-- into a sequenced Core expression using >>>= and a left fold. (It's a left fold that has
-- information—specifically the LHS to assign—flowing through it rightward.)
expressionListToSingleName :: Py.ExpressionList a -> Maybe Text
expressionListToSingleName Py.ExpressionList { Py.extraChildren =
[ Py.PrimaryExpressionExpression (Py.IdentifierPrimaryExpression (Py.Identifier { Py.bytes = name }))
]
} = Just name
expressionListToSingleName _ = Nothing
-- RHS represents the right-hand-side of an assignment that we get out of tree-sitter.
-- Desugared is the "terminal" node in a sequence of assignments, i.e. given a = b = c,
-- c will be the terminal node. It is never an assignment.
type RHS a = Either (Py.Assignment a) (Either (Py.AugmentedAssignment a) (Desugared a))
type Desugared a = Either (Py.ExpressionList a) (Py.Yield a)
desugar :: Show a => RHS a -> Maybe ([Name], Desugared a)
desugar = \case
Left it@Py.Assignment { left = lhs
, right
} -> do
Just name <- pure $ expressionListToSingleName lhs
(names, item) <- right >>= desugar
let current = name
pure (current:names, item)
Right (Left _aug) -> error "augmented assignment case not done"
Left it@Py.Assignment { left = OneExpression name, right} ->
let located = name
in fmap (first (located:)) (right >>= desugar)
Right (Right any) -> Just ([], any)
e -> error ("Bug: died with " <> show e <> " in desugar")
instance Compile (Py.Assignment Span) where
compileCC it@Py.Assignment
{ Py.left = (expressionListToSingleName -> Just name)
{ Py.left = OneExpression name
, Py.right = Just rhs
} cc = do
Just (names, val) <- pure (desugar rhs)
@ -146,6 +162,8 @@ instance Compile (Py.Assignment Span) where
compileCC other _ = fail ("Unhandled assignment case: " <> show other)
-- End assignment compilation
instance Compile (Py.AugmentedAssignment Span)
instance Compile (Py.Await Span)
instance Compile (Py.BinaryOperator Span)