Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 1fc29e8

Browse files
committed
Evaluate terms as directly as possible.
1 parent cd62a56 commit 1fc29e8

File tree

1 file changed

+56
-60
lines changed
  • semantic-analysis/src/Analysis/Syntax

1 file changed

+56
-60
lines changed

semantic-analysis/src/Analysis/Syntax/Python.hs

Lines changed: 56 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,26 @@ module Analysis.Syntax.Python
1313
, parse
1414
) where
1515

16-
import Analysis.Effect.Domain hiding ((:>>>), (>>>))
17-
import qualified Analysis.Effect.Domain as D
16+
import Analysis.Effect.Domain hiding ((:>>>))
1817
import qualified Analysis.Effect.Statement as S
1918
import Analysis.Name
2019
import Analysis.Reference
21-
import qualified Analysis.Syntax as T
2220
import Analysis.VM
2321
import Control.Effect.Labelled
2422
import Control.Effect.Reader
23+
import Control.Monad (foldM)
24+
import Data.Foldable (for_)
2525
import Data.Function (fix)
2626
import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
27+
import Data.Maybe (mapMaybe)
2728
import Data.Text (Text, pack)
28-
import qualified Language.Python.Common.AST as Py
29+
import qualified Language.Python.Common as Py
2930
import Language.Python.Version3.Parser
30-
import Source.Span (Span)
31+
import Source.Span (Pos (..), Span (..), point)
3132
import System.FilePath (takeBaseName)
3233

3334
-- Syntax
3435

35-
type Term = T.Term Python Name
36-
3736
data Python t
3837
= Noop
3938
| Iff t t t
@@ -50,74 +49,71 @@ data Python t
5049

5150
infixl 1 :>>
5251

52+
data Term
53+
= Module (Py.Module Py.SrcSpan)
54+
| Statement (Py.Statement Py.SrcSpan)
55+
| Expr (Py.Expr Py.SrcSpan)
56+
| Argument (Py.Argument Py.SrcSpan)
57+
5358

5459
-- Abstract interpretation
5560

56-
eval0 :: (Has (Env addr) sig m, HasLabelled Store (Store addr val) sig m, Has (Dom val) sig m, Has (Reader Reference) sig m, Has S.Statement sig m) => Term -> m val
61+
eval0 :: (Has (Env addr) sig m, HasLabelled Store (Store addr val) sig m, Has (Dom val) sig m, Has (Reader Reference) sig m, Has S.Statement sig m, MonadFail m) => Term -> m val
5762
eval0 = fix eval
5863

5964
eval
60-
:: (Has (Env addr) sig m, HasLabelled Store (Store addr val) sig m, Has (Dom val) sig m, Has (Reader Reference) sig m, Has S.Statement sig m)
65+
:: (Has (Env addr) sig m, HasLabelled Store (Store addr val) sig m, Has (Dom val) sig m, Has (Reader Reference) sig m, Has S.Statement sig m, MonadFail m)
6166
=> (Term -> m val)
6267
-> (Term -> m val)
6368
eval eval = \case
64-
T.Var n -> lookupEnv n >>= maybe (dvar n) fetch
65-
T.Term s -> case s of
66-
Noop -> dunit
67-
Iff c t e -> do
68-
c' <- eval c
69-
dif c' (eval t) (eval e)
70-
Bool b -> dbool b
71-
String s -> dstring s
72-
Throw e -> eval e >>= ddie
73-
Let n v b -> do
74-
v' <- eval v
75-
let' n v' (eval b)
76-
t :>> u -> do
77-
t' <- eval t
78-
u' <- eval u
79-
t' D.>>> u'
80-
Import ns -> S.simport ns >> dunit
81-
Function n ps b -> letrec n (dabs ps (foldr (\ (p, a) m -> let' p a m) (eval b) . zip ps))
82-
Call f as -> do
83-
f' <- eval f
84-
as' <- traverse eval as
85-
dapp f' as'
86-
Locate s t -> local (setSpan s) (eval t)
69+
Module (Py.Module ss) -> suite ss
70+
Statement (Py.Import is sp) -> setSpan sp $ do
71+
for_ is $ \ Py.ImportItem{ Py.import_item_name = ns } -> case nonEmpty ns of
72+
Nothing -> pure ()
73+
Just ss -> S.simport (pack . Py.ident_string <$> ss)
74+
dunit
75+
Statement (Py.Pass sp) -> setSpan sp dunit
76+
Statement (Py.Conditional cts e sp) -> setSpan sp $ foldr (\ (c, t) e -> do
77+
c' <- eval (Expr c)
78+
dif c' (suite t) e) (suite e) cts
79+
Statement (Py.Raise (Py.RaiseV3 e) sp) -> setSpan sp $ case e of
80+
Just (e, _) -> eval (Expr e) >>= ddie -- FIXME: from clause
81+
Nothing -> dunit >>= ddie
82+
-- FIXME: RaiseV2
83+
Statement (Py.StmtExpr e sp) -> setSpan sp (eval (Expr e))
84+
Statement (Py.Fun n ps _r ss sp) -> let ps' = mapMaybe (\ p -> case p of { Py.Param n _ _ _ -> Just (ident n) ; _ -> Nothing}) ps in setSpan sp $ letrec (ident n) (dabs ps' (foldr (\ (p, a) m -> let' p a m) (suite ss) . zip ps'))
85+
Expr (Py.Var n sp) -> setSpan sp $ let n' = ident n in lookupEnv n' >>= maybe (dvar n') fetch
86+
Expr (Py.Bool b sp) -> setSpan sp $ dbool b
87+
Expr (Py.Strings ss sp) -> setSpan sp $ dstring (pack (mconcat ss))
88+
Expr (Py.Call f as sp) -> setSpan sp $ do
89+
f' <- eval (Expr f)
90+
as' <- traverse (eval . Argument) as
91+
dapp f' as'
92+
Argument (Py.ArgExpr e sp) -> setSpan sp $ eval (Expr e)
93+
-- FIXME: support keyword args &c.
94+
_ -> fail "TBD"
8795
where
88-
setSpan s r = r{ refSpan = s }
89-
90-
(>>>) :: T.Term Python v -> T.Term Python v -> T.Term Python v
91-
l >>> r = T.Term (l :>> r)
92-
93-
noop :: T.Term Python v
94-
noop = T.Term Noop
95-
96-
iff :: T.Term Python v -> T.Term Python v -> T.Term Python v -> T.Term Python v
97-
iff c t e = T.Term (Iff c t e)
96+
setSpan s = case fromSpan s of
97+
Just s -> local (\ r -> r{ refSpan = s })
98+
_ -> id
99+
fromSpan Py.SpanEmpty = Nothing
100+
fromSpan (Py.SpanPoint _ l c) = Just (point (Pos l c))
101+
fromSpan (Py.SpanCoLinear _ l c1 c2) = Just (Span (Pos l c1) (Pos l c2))
102+
fromSpan (Py.SpanMultiLine _ l1 l2 c1 c2) = Just (Span (Pos l1 c1) (Pos l2 c2))
103+
suite [] = dunit
104+
suite (s:ss) = do
105+
s' <- eval (Statement s)
106+
foldM (\ into each -> do
107+
each' <- eval (Statement each)
108+
into >>> each') s' ss
109+
ident = name . pack . Py.ident_string
98110

99111

100112
-- Parsing
101113

102-
parse :: FilePath -> IO (T.Term Python Name)
114+
parse :: FilePath -> IO Term
103115
parse path = do
104116
src <- readFile path
105117
case parseModule src (takeBaseName path) of
106118
Left err -> fail (show err)
107-
Right (Py.Module ss, _) -> suite ss
108-
where
109-
statement :: Py.Statement annot -> IO (T.Term Python Name)
110-
statement = \case
111-
Py.Import is _ -> foldr ((>>>) . T.Term . Import) noop <$> traverse importItem is
112-
Py.Conditional cs e _ -> foldr (\ (c, t) e -> iff <$> expr c <*> suite t <*> e) (suite e) cs
113-
_ -> fail "cannot ingest this Python statement"
114-
expr :: Py.Expr annot -> IO (T.Term Python Name)
115-
expr = \case
116-
Py.Var v _ -> pure (T.Var (name (pack (ident v))))
117-
_ -> fail "cannot ingest this Python expression"
118-
ident :: Py.Ident annot -> String
119-
ident (Py.Ident s _) = s
120-
importItem :: Py.ImportItem annot -> IO (NonEmpty Text)
121-
importItem Py.ImportItem{ Py.import_item_name = ns } = maybe (fail "") pure (nonEmpty (map (pack . ident) ns)) -- FIXME: "as" names
122-
suite :: [Py.Statement annot] -> IO (T.Term Python Name)
123-
suite ss = foldr (>>>) noop <$> traverse statement ss
119+
Right (Py.Module ss, _) -> pure (Module (Py.Module ss))

0 commit comments

Comments
 (0)