1
1
mirror of https://github.com/github/semantic.git synced 2024-11-24 08:54:07 +03:00

Merge branch 'master' into core-factoring

This commit is contained in:
Rob Rix 2019-10-10 17:14:42 -04:00
commit d2c1d879c0
No known key found for this signature in database
GPG Key ID: F188A01508EA1CF7
3 changed files with 35 additions and 48 deletions

View File

@ -5,7 +5,6 @@
module Language.Python.Core module Language.Python.Core
( toplevelCompile ( toplevelCompile
, Bindings , Bindings
, SourcePath
) where ) where
import Prelude hiding (fail) import Prelude hiding (fail)
@ -13,6 +12,7 @@ import Prelude hiding (fail)
import AST.Element import AST.Element
import Control.Effect hiding ((:+:)) import Control.Effect hiding ((:+:))
import Control.Effect.Reader import Control.Effect.Reader
import Control.Monad ((>=>))
import Control.Monad.Fail import Control.Monad.Fail
import Core.Core as Core import Core.Core as Core
import Core.Name as Name import Core.Name as Name
@ -20,16 +20,10 @@ import Core.Stack (Stack)
import qualified Core.Stack as Stack import qualified Core.Stack as Stack
import Data.Coerce import Data.Coerce
import Data.Foldable import Data.Foldable
import Data.String (IsString)
import Data.Text (Text)
import GHC.Records import GHC.Records
import Source.Span (Span) import Source.Span (Span)
import qualified TreeSitter.Python.AST as Py import qualified TreeSitter.Python.AST as Py
-- | Access to the current filename as Text to stick into location annotations.
newtype SourcePath = SourcePath { rawPath :: Text }
deriving (Eq, IsString, Show)
-- | Keeps track of the current scope's bindings (so that we can, when -- | Keeps track of the current scope's bindings (so that we can, when
-- compiling a class or module, return the list of bound variables as -- compiling a class or module, return the list of bound variables as
-- a Core record so that all immediate definitions are exposed) -- a Core record so that all immediate definitions are exposed)
@ -63,27 +57,25 @@ class Compile (py :: * -> *) where
-- FIXME: rather than failing the compilation process entirely -- FIXME: rather than failing the compilation process entirely
-- with MonadFail, we should emit core that represents failure -- with MonadFail, we should emit core that represents failure
compile :: ( CoreSyntax syn t compile :: ( CoreSyntax syn t
, Member (Reader SourcePath) sig
, Member (Reader Bindings) sig , Member (Reader Bindings) sig
, Carrier sig m , Carrier sig m
, MonadFail m , MonadFail m
) )
=> py Span => py Span
-> m (t Name) -> (t Name -> m (t Name))
-> m (t Name) -> (t Name -> m (t Name))
default compile :: (MonadFail m, Show (py Span)) => py Span -> m (t Name) -> m (t Name) default compile :: (MonadFail m, Show (py Span)) => py Span -> (t Name -> m (t Name)) -> (t Name -> m (t Name))
compile a _ = defaultCompile a compile a _ _ = defaultCompile a
toplevelCompile :: ( CoreSyntax syn t toplevelCompile :: ( CoreSyntax syn t
, Member (Reader SourcePath) sig
, Member (Reader Bindings) sig , Member (Reader Bindings) sig
, Carrier sig m , Carrier sig m
, MonadFail m , MonadFail m
) )
=> Py.Module Span => Py.Module Span
-> m (t Name) -> m (t Name)
toplevelCompile = flip compile (pure none) toplevelCompile py = compile py pure none
-- | TODO: This is not right, it should be a reference to a Preluded -- | TODO: This is not right, it should be a reference to a Preluded
-- NoneType instance, but it will do for now. -- NoneType instance, but it will do for now.
@ -136,7 +128,7 @@ data Located a = Located Span a
-- Desugaring an RHS involves walking as deeply as possible into an -- Desugaring an RHS involves walking as deeply as possible into an
-- assignment, storing the names we encounter as we go and eventually -- assignment, storing the names we encounter as we go and eventually
-- returning a terminal expression. We have to keep track of which -- returning a terminal expression. We have to keep track of which
desugar :: (Member (Reader SourcePath) sig, Carrier sig m, MonadFail m) desugar :: MonadFail m
=> [Located Name] => [Located Name]
-> RHS Span -> RHS Span
-> m ([Located Name], Desugared Span) -> m ([Located Name], Desugared Span)
@ -167,12 +159,11 @@ instance Compile Py.Assignment where
{ left = SingleIdentifier name { left = SingleIdentifier name
, right = Just rhs , right = Just rhs
, ann , ann
} cc = do } cc next = do
(names, val) <- desugar [Located ann name] rhs (names, val) <- desugar [Located ann name] rhs
-- BUG: ignoring the continuation here compile val pure next >>= foldr collapseDesugared cc names >>= locate it
compile val (pure none) >>= foldr collapseDesugared (const cc) names >>= locate it
compile other _ = fail ("Unhandled assignment case: " <> show other) compile other _ _ = fail ("Unhandled assignment case: " <> show other)
-- End assignment compilation -- End assignment compilation
@ -181,7 +172,7 @@ instance Compile Py.Await
instance Compile Py.BinaryOperator instance Compile Py.BinaryOperator
instance Compile Py.Block where instance Compile Py.Block where
compile it@Py.Block{ Py.extraChildren = body} cc = locate it =<< foldr compile cc body compile it@Py.Block{ Py.extraChildren = body} cc = foldr compile cc body >=> locate it
instance Compile Py.BooleanOperator instance Compile Py.BooleanOperator
instance Compile Py.BreakStatement instance Compile Py.BreakStatement
@ -207,17 +198,17 @@ instance Compile Py.ExpressionStatement where
compile it@Py.ExpressionStatement compile it@Py.ExpressionStatement
{ Py.extraChildren = children { Py.extraChildren = children
} cc = do } cc = do
foldr compile cc children >>= locate it foldr compile cc children >=> locate it
instance Compile Py.ExpressionList where instance Compile Py.ExpressionList where
compile it@Py.ExpressionList { Py.extraChildren = [child] } cc compile it@Py.ExpressionList { Py.extraChildren = [child] } cc
= compile child cc >>= locate it = compile child cc >=> locate it
compile Py.ExpressionList { Py.extraChildren = items } _ compile Py.ExpressionList { Py.extraChildren = items } _
= fail ("unimplemented: ExpressionList of length " <> show items) = const (fail ("unimplemented: ExpressionList of length " <> show items))
instance Compile Py.False where instance Compile Py.False where
compile it _ = locate it $ bool False compile it cc _ = locate it (bool False) >>= cc
instance Compile Py.Float instance Compile Py.Float
instance Compile Py.ForStatement instance Compile Py.ForStatement
@ -227,16 +218,16 @@ instance Compile Py.FunctionDefinition where
{ name = Py.Identifier _ann1 name { name = Py.Identifier _ann1 name
, parameters = Py.Parameters _ann2 parameters , parameters = Py.Parameters _ann2 parameters
, body , body
} cc = do } cc next = do
-- Compile each of the parameters, then the body. -- Compile each of the parameters, then the body.
parameters' <- traverse param parameters parameters' <- traverse param parameters
body' <- compile body (pure none) body' <- compile body pure next
-- Build a lambda. -- Build a lambda.
located <- locate it (lams parameters' body') located <- locate it (lams parameters' body')
-- Give it a name (below), then augment the current continuation -- Give it a name (below), then augment the current continuation
-- with the new name (with 'def'), so that calling contexts know -- with the new name (with 'def'), so that calling contexts know
-- that we have built an exportable definition. -- that we have built an exportable definition.
assigning located <$> local (def (Name name)) cc assigning located <$> local (def (Name name)) (cc next)
where param (Py.Parameter (Prj (Py.Identifier _pann pname))) = pure . named' . Name $ pname where param (Py.Parameter (Prj (Py.Identifier _pann pname))) = pure . named' . Name $ pname
param x = unimplemented x param x = unimplemented x
unimplemented x = fail $ "unimplemented: " <> show x unimplemented x = fail $ "unimplemented: " <> show x
@ -247,17 +238,16 @@ instance Compile Py.GeneratorExpression
instance Compile Py.GlobalStatement instance Compile Py.GlobalStatement
instance Compile Py.Identifier where instance Compile Py.Identifier where
compile Py.Identifier { text } _ = pure . pure . Name $ text compile Py.Identifier { text } cc _ = cc . pure . Name $ text
instance Compile Py.IfStatement where instance Compile Py.IfStatement where
compile it@Py.IfStatement{ condition, consequence, alternative} cc = compile it@Py.IfStatement{ condition, consequence, alternative} cc next =
locate it =<< if' locate it =<< if' <$> compile condition pure next
<$> compile condition (pure none) <*> compile consequence cc next
<*> compile consequence cc <*> foldr clause (cc next) alternative
<*> foldr clause cc alternative where clause (R1 Py.ElseClause{ body }) _ = compile body cc next
where clause (R1 Py.ElseClause{ body }) _ = compile body cc
clause (L1 Py.ElifClause{ condition, consequence }) rest = clause (L1 Py.ElifClause{ condition, consequence }) rest =
if' <$> compile condition (pure none) <*> compile consequence cc <*> rest if' <$> compile condition pure next <*> compile consequence cc next <*> rest
instance Compile Py.ImportFromStatement instance Compile Py.ImportFromStatement
@ -268,17 +258,17 @@ instance Compile Py.List
instance Compile Py.ListComprehension instance Compile Py.ListComprehension
instance Compile Py.Module where instance Compile Py.Module where
compile it@Py.Module { Py.extraChildren = stmts } _cc = do compile it@Py.Module { Py.extraChildren = stmts } _cc =
-- This action gets passed to compile, which means it is the -- This action gets passed to compile, which means it is the
-- final action taken after the compiling fold finishes. It takes -- final action taken after the compiling fold finishes. It takes
-- care of listening for the current set of bound variables (which -- care of listening for the current set of bound variables (which
-- is augmented by assignments and function definitions) and -- is augmented by assignments and function definitions) and
-- creating a record corresponding to those bindings. -- creating a record corresponding to those bindings.
let buildRecord = do let buildRecord _ = do
bindings <- asks @Bindings (toList . unBindings) bindings <- asks @Bindings (toList . unBindings)
let buildName n = (n, pure n) let buildName n = (n, pure n)
pure . record . fmap buildName $ bindings pure . record . fmap buildName $ bindings
foldr compile buildRecord stmts >>= locate it in foldr compile buildRecord stmts >=> locate it
instance Compile Py.NamedExpression instance Compile Py.NamedExpression
instance Compile Py.None instance Compile Py.None
@ -287,17 +277,16 @@ instance Compile Py.NotOperator
instance Compile Py.ParenthesizedExpression instance Compile Py.ParenthesizedExpression
instance Compile Py.PassStatement where instance Compile Py.PassStatement where
compile it@Py.PassStatement {} _ = locate it $ Core.unit compile it@Py.PassStatement {} cc _ = locate it Core.unit >>= cc
deriving instance Compile Py.PrimaryExpression deriving instance Compile Py.PrimaryExpression
instance Compile Py.PrintStatement instance Compile Py.PrintStatement
instance Compile Py.ReturnStatement where instance Compile Py.ReturnStatement where
compile it@Py.ReturnStatement { Py.extraChildren = vals } _ = case vals of compile it@Py.ReturnStatement { Py.extraChildren = vals } _ next = case vals of
Nothing -> locate it $ none Nothing -> locate it $ none
-- BUG: ignoring the continuation here Just Py.ExpressionList { extraChildren = [val] } -> compile val pure next >>= locate it
Just Py.ExpressionList { extraChildren = [val] } -> compile val (pure none) >>= locate it
Just Py.ExpressionList { extraChildren = vals } -> fail ("unimplemented: return statement returning " <> show (length vals) <> " values") Just Py.ExpressionList { extraChildren = vals } -> fail ("unimplemented: return statement returning " <> show (length vals) <> " values")
@ -311,14 +300,14 @@ instance Compile Py.String
instance Compile Py.Subscript instance Compile Py.Subscript
instance Compile Py.True where instance Compile Py.True where
compile it _ = locate it $ bool True compile it cc _next = locate it (bool True) >>= cc
instance Compile Py.TryStatement instance Compile Py.TryStatement
instance Compile Py.Tuple where instance Compile Py.Tuple where
compile it@Py.Tuple { Py.extraChildren = [] } _ = locate it unit compile it@Py.Tuple { Py.extraChildren = [] } cc _ = locate it unit >>= cc
compile it _ compile it _ _
= fail ("Unimplemented: non-empty tuple " <> show it) = fail ("Unimplemented: non-empty tuple " <> show it)
instance Compile Py.UnaryOperator instance Compile Py.UnaryOperator

View File

@ -25,7 +25,6 @@ import Data.Foldable
import Data.Function import Data.Function
import Data.List (sort) import Data.List (sort)
import Data.Maybe import Data.Maybe
import Data.String (fromString)
import GHC.Stack import GHC.Stack
import qualified Language.Python.Core as Py import qualified Language.Python.Core as Py
import Prelude hiding (fail) import Prelude hiding (fail)
@ -96,7 +95,6 @@ fixtureTestTreeForFile fp = HUnit.testCaseSteps (Path.toString fp) $ \step -> wi
result <- ByteString.readFile (Path.toString fullPath) >>= TS.parseByteString TSP.tree_sitter_python result <- ByteString.readFile (Path.toString fullPath) >>= TS.parseByteString TSP.tree_sitter_python
let coreResult = Control.Effect.run let coreResult = Control.Effect.run
. runFail . runFail
. runReader (fromString @Py.SourcePath . Path.toString $ fp)
. runReader @Py.Bindings mempty . runReader @Py.Bindings mempty
. Py.toplevelCompile . Py.toplevelCompile
<$> result <$> result

View File

@ -1,3 +1,3 @@
# CHECK-JQ: .scope == {} # CHECK-JQ: .scope == {}
# CHECK-TREE: (#unit) # CHECK-TREE: #record{}
() ()