Major overhaul
Can now parse a much larger part of the language. The reference finding mechanism now seems more robust / less hacky. Bugs remain, however!
This commit is contained in:
parent
a0c574b53a
commit
f8163f99c7
|
@ -9,7 +9,8 @@ module Data.Language.Ruby
|
||||||
import Data.Aeson (eitherDecode)
|
import Data.Aeson (eitherDecode)
|
||||||
import Data.ByteString.Lazy (ByteString)
|
import Data.ByteString.Lazy (ByteString)
|
||||||
import Data.Language.Ruby.AST
|
import Data.Language.Ruby.AST
|
||||||
import Frelude
|
import Frelude hiding (String)
|
||||||
|
import qualified Frelude
|
||||||
import System.IO (hFlush)
|
import System.IO (hFlush)
|
||||||
import System.IO.Temp (withSystemTempFile)
|
import System.IO.Temp (withSystemTempFile)
|
||||||
import System.Process (readProcess)
|
import System.Process (readProcess)
|
||||||
|
@ -20,16 +21,16 @@ decodeFail s = case eitherDecode s of
|
||||||
Left err -> Frelude.fail err
|
Left err -> Frelude.fail err
|
||||||
Right a -> pure a
|
Right a -> pure a
|
||||||
|
|
||||||
runRubyParseFile :: FilePath -> IO String
|
runRubyParseFile :: FilePath -> IO Frelude.String
|
||||||
runRubyParseFile p = sh "ruby-parse" ["--emit-json", "--25", p]
|
runRubyParseFile p = sh "ruby-parse" ["--emit-json", "--25", p]
|
||||||
|
|
||||||
runRubyParse :: ByteString -> IO String
|
runRubyParse :: ByteString -> IO Frelude.String
|
||||||
runRubyParse s = withSystemTempFile "rubyhs" $ \p h -> do
|
runRubyParse s = withSystemTempFile "rubyhs" $ \p h -> do
|
||||||
ByteString.hPut h s
|
ByteString.hPut h s
|
||||||
hFlush h
|
hFlush h
|
||||||
runRubyParseFile p
|
runRubyParseFile p
|
||||||
|
|
||||||
sh :: String -> [String] -> IO String
|
sh :: Frelude.String -> [Frelude.String] -> IO Frelude.String
|
||||||
sh cmd a = readProcess cmd a mempty
|
sh cmd a = readProcess cmd a mempty
|
||||||
|
|
||||||
parseFile :: FromJSON a => FilePath -> IO a
|
parseFile :: FromJSON a => FilePath -> IO a
|
||||||
|
|
|
@ -1,30 +1,39 @@
|
||||||
{-# LANGUAGE DuplicateRecordFields, OverloadedLists #-}
|
{-# LANGUAGE DuplicateRecordFields, OverloadedLists #-}
|
||||||
{-# OPTIONS_GHC -Wall #-}
|
{-# OPTIONS_GHC -Wall #-}
|
||||||
module Data.Language.Ruby.AST
|
module Data.Language.Ruby.AST
|
||||||
( Args(..)
|
( Begin(..)
|
||||||
, Begin(..)
|
|
||||||
, Statement(..)
|
, Statement(..)
|
||||||
, Function(..)
|
, Def(..)
|
||||||
, Module(..)
|
, Module(..)
|
||||||
, Name(..)
|
|
||||||
, Send(..)
|
, Send(..)
|
||||||
, Namespace(..)
|
, Const(..)
|
||||||
, Block(..)
|
, Block(..)
|
||||||
, Casgn(..)
|
, Casgn(..)
|
||||||
, RArray(..)
|
, Array(..)
|
||||||
, RArgs(..)
|
, Args(..)
|
||||||
, Anything(..)
|
, Anything(..)
|
||||||
, Sym(..)
|
, Sym(..)
|
||||||
|
, String(..)
|
||||||
|
, Str(..)
|
||||||
|
, Lvasgn(..)
|
||||||
|
, Lvar(..)
|
||||||
|
, Ivar(..)
|
||||||
|
, Atom(..)
|
||||||
|
, Defs(..)
|
||||||
|
, Self(..)
|
||||||
|
, Nil(..)
|
||||||
|
, Cbase
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Aeson (parseJSON, Value(..), withArray)
|
import Data.Aeson (parseJSON, Value(Null,Object,Number,Bool), withArray)
|
||||||
import Frelude
|
import Frelude hiding (String)
|
||||||
|
import qualified Frelude
|
||||||
import qualified Data.Aeson.Types as Aeson
|
import qualified Data.Aeson.Types as Aeson
|
||||||
import qualified Data.Vector as Vector
|
import qualified Data.Vector as Vector
|
||||||
import Data.Coerce
|
import Data.Coerce
|
||||||
import Data.Word
|
import Data.Word
|
||||||
|
|
||||||
kebabCase :: String -> String
|
kebabCase :: Frelude.String -> Frelude.String
|
||||||
kebabCase = Aeson.camelTo2 '-'
|
kebabCase = Aeson.camelTo2 '-'
|
||||||
|
|
||||||
aesonOptions :: Aeson.Options
|
aesonOptions :: Aeson.Options
|
||||||
|
@ -46,19 +55,27 @@ deriving newtype instance Monoid Begin
|
||||||
|
|
||||||
instance FromJSON Begin where
|
instance FromJSON Begin where
|
||||||
parseJSON = withArray "Begin" $ \as -> case Vector.toList as of
|
parseJSON = withArray "Begin" $ \as -> case Vector.toList as of
|
||||||
(String "begin":xs) -> Begin <$> traverse parseJSON xs
|
(Aeson.String "begin":xs) -> Begin <$> traverse parseJSON xs
|
||||||
_ -> Begin . pure <$> parseJSON (Array as)
|
_ -> Begin . pure <$> parseJSON (Aeson.Array as)
|
||||||
|
|
||||||
-- Should be 'expression'
|
-- Should be 'expression'
|
||||||
data Statement
|
data Statement
|
||||||
= StmtModule Module
|
= StmtModule Module
|
||||||
| StmtFunction Function
|
| StmtDef Def
|
||||||
|
| StmtDefs Defs
|
||||||
| StmtSend Send
|
| StmtSend Send
|
||||||
| StmtBlock Block
|
| StmtBlock Block
|
||||||
| StmtConst Namespace
|
| StmtConst Const
|
||||||
| StmtCasgn Casgn
|
| StmtCasgn Casgn
|
||||||
| StmtArray RArray
|
| StmtArray Array
|
||||||
| StmtSym Sym
|
| StmtSym Sym
|
||||||
|
| StmtStr Str
|
||||||
|
| StmtLvasgn Lvasgn
|
||||||
|
| StmtLvar Lvar
|
||||||
|
| StmtIvar Ivar
|
||||||
|
| StmtSelf Self
|
||||||
|
| StmtNil Nil
|
||||||
|
| StmtCbase Cbase
|
||||||
-- TODO Get rid of this
|
-- TODO Get rid of this
|
||||||
| StmtAnything Anything
|
| StmtAnything Anything
|
||||||
|
|
||||||
|
@ -72,29 +89,47 @@ instance ToJSON Statement where
|
||||||
opts = aesonOptions { Aeson.constructorTagModifier = go }
|
opts = aesonOptions { Aeson.constructorTagModifier = go }
|
||||||
go = \case
|
go = \case
|
||||||
"StmtModule" -> "module"
|
"StmtModule" -> "module"
|
||||||
"StmtFunction" -> "function"
|
"StmtDef" -> "def"
|
||||||
|
"StmtDefs" -> "defs"
|
||||||
"StmtSend" -> "send"
|
"StmtSend" -> "send"
|
||||||
"StmtBlock" -> "block"
|
"StmtBlock" -> "block"
|
||||||
"StmtConst" -> "const"
|
"StmtConst" -> "const"
|
||||||
"StmtCasgn" -> "casgn"
|
"StmtCasgn" -> "casgn"
|
||||||
"StmtArray" -> "array"
|
"StmtArray" -> "array"
|
||||||
"StmtSym" -> "sym"
|
"StmtSym" -> "sym"
|
||||||
|
"StmtStr" -> "str"
|
||||||
|
"StmtLvasgn" -> "lvasgn"
|
||||||
|
"StmtLvar" -> "lvar"
|
||||||
|
"StmtIvar" -> "ivar"
|
||||||
|
"StmtSelf" -> "self"
|
||||||
|
"StmtNil" -> "nil"
|
||||||
|
"StmtCbase" -> "cbase"
|
||||||
x -> x
|
x -> x
|
||||||
|
|
||||||
instance FromJSON Statement where
|
instance FromJSON Statement where
|
||||||
parseJSON v
|
parseJSON v
|
||||||
= (StmtModule <$> parseJSON v)
|
= (StmtModule <$> parseJSON v)
|
||||||
<|> (StmtFunction <$> parseJSON v)
|
<|> (StmtDef <$> parseJSON v)
|
||||||
|
<|> (StmtDefs <$> parseJSON v)
|
||||||
<|> (StmtSend <$> parseJSON v)
|
<|> (StmtSend <$> parseJSON v)
|
||||||
<|> (StmtBlock <$> parseJSON v)
|
<|> (StmtBlock <$> parseJSON v)
|
||||||
<|> (StmtConst <$> parseJSON v)
|
<|> (StmtConst <$> parseJSON v)
|
||||||
<|> (StmtCasgn <$> parseJSON v)
|
<|> (StmtCasgn <$> parseJSON v)
|
||||||
<|> (StmtArray <$> parseJSON v)
|
<|> (StmtArray <$> parseJSON v)
|
||||||
|
<|> (StmtSym <$> parseJSON v)
|
||||||
|
<|> (StmtStr <$> parseJSON v)
|
||||||
|
<|> (StmtLvasgn <$> parseJSON v)
|
||||||
|
<|> (StmtLvar <$> parseJSON v)
|
||||||
|
<|> (StmtIvar <$> parseJSON v)
|
||||||
|
<|> (StmtSelf <$> parseJSON v)
|
||||||
|
<|> (StmtNil <$> parseJSON v)
|
||||||
|
<|> (StmtCbase <$> parseJSON v)
|
||||||
<|> (StmtAnything <$> parseJSON v)
|
<|> (StmtAnything <$> parseJSON v)
|
||||||
|
|
||||||
data Casgn = Casgn
|
data Casgn = Casgn
|
||||||
{ name :: Name
|
{ context :: Statement
|
||||||
, statement :: Statement
|
, atom :: Atom
|
||||||
|
, rhs :: Statement
|
||||||
}
|
}
|
||||||
deriving stock instance Show Casgn
|
deriving stock instance Show Casgn
|
||||||
deriving stock instance Ord Casgn
|
deriving stock instance Ord Casgn
|
||||||
|
@ -104,26 +139,27 @@ instance ToJSON Casgn where
|
||||||
toEncoding = Aeson.genericToEncoding aesonOptions
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
instance FromJSON Casgn where
|
instance FromJSON Casgn where
|
||||||
parseJSON = withArray "Module" $ \case
|
parseJSON = withArray "Module" $ \case
|
||||||
[String "casgn", _, name, statement]
|
[Aeson.String "casgn", context, atom, rhs]
|
||||||
-> Casgn
|
-> Casgn
|
||||||
<$> parseJSON name
|
<$> parseJSON context
|
||||||
<*> parseJSON statement
|
<*> parseJSON atom
|
||||||
|
<*> parseJSON rhs
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
|
|
||||||
data RArray = RArray
|
data Array = Array
|
||||||
{ statements :: [Statement]
|
{ statements :: [Statement]
|
||||||
}
|
}
|
||||||
deriving stock instance Show RArray
|
deriving stock instance Show Array
|
||||||
deriving stock instance Ord RArray
|
deriving stock instance Ord Array
|
||||||
deriving stock instance Eq RArray
|
deriving stock instance Eq Array
|
||||||
deriving stock instance Generic RArray
|
deriving stock instance Generic Array
|
||||||
instance ToJSON RArray where
|
instance ToJSON Array where
|
||||||
toEncoding = Aeson.genericToEncoding aesonOptions
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
instance FromJSON RArray where
|
instance FromJSON Array where
|
||||||
parseJSON = withArray "RArray" $ \as -> case Vector.toList as of
|
parseJSON = withArray "Array" $ \as -> case Vector.toList as of
|
||||||
String "array":xs
|
Aeson.String "array":xs
|
||||||
-> RArray
|
-> Array
|
||||||
<$> traverse parseJSON xs
|
<$> traverse parseJSON xs
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
|
@ -143,7 +179,7 @@ deriving newtype instance FromJSON Anything
|
||||||
-- end
|
-- end
|
||||||
data Block = Block
|
data Block = Block
|
||||||
{ send :: Send
|
{ send :: Send
|
||||||
, args :: RArgs
|
, args :: Args
|
||||||
, begin :: Begin
|
, begin :: Begin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +191,7 @@ instance ToJSON Block where
|
||||||
toEncoding = Aeson.genericToEncoding aesonOptions
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
instance FromJSON Block where
|
instance FromJSON Block where
|
||||||
parseJSON = withArray "Block" $ \as -> case Vector.toList as of
|
parseJSON = withArray "Block" $ \as -> case Vector.toList as of
|
||||||
(String "block":send:args:begin:[])
|
[Aeson.String "block",send,args,begin]
|
||||||
-> Block
|
-> Block
|
||||||
<$> parseJSON send
|
<$> parseJSON send
|
||||||
<*> parseJSON args
|
<*> parseJSON args
|
||||||
|
@ -165,17 +201,17 @@ instance FromJSON Block where
|
||||||
-- | It's super confusing that I've already defined a node in my AST
|
-- | It's super confusing that I've already defined a node in my AST
|
||||||
-- called args. This one correspond to the AST node with the label
|
-- called args. This one correspond to the AST node with the label
|
||||||
-- "args" as reported by `ruby-parse`.
|
-- "args" as reported by `ruby-parse`.
|
||||||
newtype RArgs = RArgs [Arg]
|
newtype Args = Args [Arg]
|
||||||
|
|
||||||
deriving stock instance Show RArgs
|
deriving stock instance Show Args
|
||||||
deriving stock instance Ord RArgs
|
deriving stock instance Ord Args
|
||||||
deriving stock instance Eq RArgs
|
deriving stock instance Eq Args
|
||||||
deriving stock instance Generic RArgs
|
deriving stock instance Generic Args
|
||||||
instance ToJSON RArgs where
|
instance ToJSON Args where
|
||||||
toEncoding = Aeson.genericToEncoding aesonOptions
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
instance FromJSON RArgs where
|
instance FromJSON Args where
|
||||||
parseJSON = withArray "RArgs" $ \as -> case Vector.toList as of
|
parseJSON = withArray "Args" $ \as -> case Vector.toList as of
|
||||||
(String "args":xs) -> RArgs <$> traverse parseJSON xs
|
(Aeson.String "args":xs) -> Args <$> traverse parseJSON xs
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
data Arg = Arg Atom | KWArg Atom
|
data Arg = Arg Atom | KWArg Atom
|
||||||
|
@ -195,8 +231,8 @@ instance ToJSON Arg where
|
||||||
|
|
||||||
instance FromJSON Arg where
|
instance FromJSON Arg where
|
||||||
parseJSON = withArray "Arg" $ \as -> case Vector.toList as of
|
parseJSON = withArray "Arg" $ \as -> case Vector.toList as of
|
||||||
[String "arg" , symbol] -> Arg <$> parseJSON symbol
|
[Aeson.String "arg" , symbol] -> Arg <$> parseJSON symbol
|
||||||
[String "kwarg" , symbol] -> KWArg <$> parseJSON symbol
|
[Aeson.String "kwarg" , symbol] -> KWArg <$> parseJSON symbol
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
newtype Atom = Atom Text
|
newtype Atom = Atom Text
|
||||||
|
@ -210,30 +246,30 @@ instance ToJSON Atom where
|
||||||
|
|
||||||
instance FromJSON Atom where
|
instance FromJSON Atom where
|
||||||
parseJSON = \case
|
parseJSON = \case
|
||||||
String s -> pure $ Atom s
|
Aeson.String s -> pure $ Atom s
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
newtype Namespace = Namespace [Name]
|
data Const = Const
|
||||||
|
{ context :: Statement
|
||||||
|
, atom :: Atom
|
||||||
|
}
|
||||||
|
|
||||||
deriving newtype instance Semigroup Namespace
|
deriving stock instance Show Const
|
||||||
deriving newtype instance Monoid Namespace
|
deriving stock instance Ord Const
|
||||||
deriving stock instance Show Namespace
|
deriving stock instance Eq Const
|
||||||
deriving stock instance Ord Namespace
|
deriving stock instance Generic Const
|
||||||
deriving stock instance Eq Namespace
|
instance ToJSON Const where
|
||||||
deriving stock instance Generic Namespace
|
|
||||||
instance ToJSON Namespace where
|
|
||||||
toEncoding = Aeson.genericToEncoding aesonOptions
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
|
||||||
instance FromJSON Namespace where
|
instance FromJSON Const where
|
||||||
parseJSON = \case
|
parseJSON = withArray "Send" $ \case -- \ as -> case Vector.toList as of
|
||||||
Null -> pure mempty
|
[Aeson.String "const", context, atom] -> Const <$> parseJSON context <*> parseJSON atom
|
||||||
Array [String "const", namespace, String name] -> (<> Namespace [Name $ String name]) <$> parseJSON namespace
|
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
data Send = Send
|
data Send = Send
|
||||||
{ args :: Args
|
{ context :: Statement
|
||||||
, namespace :: Namespace
|
, atom :: Atom
|
||||||
, name :: Name
|
, args :: [Statement]
|
||||||
}
|
}
|
||||||
|
|
||||||
deriving stock instance Show Send
|
deriving stock instance Show Send
|
||||||
|
@ -245,15 +281,15 @@ instance ToJSON Send where
|
||||||
|
|
||||||
instance FromJSON Send where
|
instance FromJSON Send where
|
||||||
parseJSON = withArray "Send" $ \ as -> case Vector.toList as of
|
parseJSON = withArray "Send" $ \ as -> case Vector.toList as of
|
||||||
(String "send" : namespace : name : args)
|
(Aeson.String "send" : context : atom : args)
|
||||||
-> Send
|
-> Send
|
||||||
<$> parseJSON (Array $ Vector.fromList args)
|
<$> parseJSON context
|
||||||
<*> parseJSON namespace
|
<*> parseJSON atom
|
||||||
<*> parseJSON name
|
<*> parseJSON (Aeson.Array $ Vector.fromList args)
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
data Module = Module
|
data Module = Module
|
||||||
{ name :: Name
|
{ name :: Const
|
||||||
, begin :: Begin
|
, begin :: Begin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,11 +302,11 @@ instance ToJSON Module where
|
||||||
|
|
||||||
instance FromJSON Module where
|
instance FromJSON Module where
|
||||||
parseJSON = withArray "Module" $ \case
|
parseJSON = withArray "Module" $ \case
|
||||||
[String "module", name, begin]
|
[Aeson.String "module", name, begin]
|
||||||
-> Module
|
-> Module
|
||||||
<$> parseJSON name
|
<$> parseJSON name
|
||||||
<*> parseMaybe begin
|
<*> parseMaybe begin
|
||||||
[String "class", name, _, begin]
|
[Aeson.String "class", name, _, begin]
|
||||||
-> Module
|
-> Module
|
||||||
<$> parseJSON name
|
<$> parseJSON name
|
||||||
<*> parseMaybe begin
|
<*> parseMaybe begin
|
||||||
|
@ -281,55 +317,67 @@ parseMaybe = \case
|
||||||
Null -> pure mempty
|
Null -> pure mempty
|
||||||
x -> parseJSON x
|
x -> parseJSON x
|
||||||
|
|
||||||
data Function = Function
|
data Def = Def
|
||||||
{ name :: Name
|
{ atom :: Atom
|
||||||
, args :: RArgs
|
, args :: Args
|
||||||
, begin :: Begin
|
, begin :: Begin
|
||||||
}
|
}
|
||||||
|
|
||||||
deriving stock instance Show Function
|
deriving stock instance Show Def
|
||||||
deriving stock instance Ord Function
|
deriving stock instance Ord Def
|
||||||
deriving stock instance Eq Function
|
deriving stock instance Eq Def
|
||||||
deriving stock instance Generic Function
|
deriving stock instance Generic Def
|
||||||
instance ToJSON Function where
|
instance ToJSON Def where
|
||||||
toEncoding = Aeson.genericToEncoding aesonOptions
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
|
||||||
data Args = Args [Statement]
|
instance FromJSON Def where
|
||||||
|
parseJSON = withArray "Def" $ \case
|
||||||
deriving stock instance Show Args
|
[Aeson.String "def", name, args, begin]
|
||||||
deriving stock instance Ord Args
|
-> Def
|
||||||
deriving stock instance Eq Args
|
|
||||||
deriving stock instance Generic Args
|
|
||||||
instance ToJSON Args where
|
|
||||||
toEncoding = Aeson.genericToEncoding aesonOptions
|
|
||||||
|
|
||||||
instance FromJSON Args where
|
|
||||||
parseJSON = withArray "Args" $ \xs -> Args <$> traverse parseJSON (toList xs)
|
|
||||||
|
|
||||||
instance FromJSON Function where
|
|
||||||
parseJSON = withArray "Function" $ \case
|
|
||||||
[String "def", name, args, begin]
|
|
||||||
-> Function
|
|
||||||
<$> parseJSON name
|
<$> parseJSON name
|
||||||
<*> parseJSON args
|
<*> parseJSON args
|
||||||
<*> parseMaybe begin
|
<*> parseMaybe begin
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
newtype Name = Name Value
|
-- | N.B.: 'Defs' is not meant to be the plural form of 'Def'!
|
||||||
|
data Defs = Defs
|
||||||
|
-- Is it really possible to put an arbitrary expression here? The
|
||||||
|
-- parser certainly allows it. E.g. defining
|
||||||
|
--
|
||||||
|
-- def (2+2).f
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- Raises the error "can't define singleton (TypeError)". We'll
|
||||||
|
-- permit it in the parser and kick the puck down the road.
|
||||||
|
{ context :: Statement
|
||||||
|
, atom :: Atom
|
||||||
|
, args :: Args
|
||||||
|
, begin :: Begin
|
||||||
|
}
|
||||||
|
|
||||||
deriving stock instance Show Name
|
deriving stock instance Show Defs
|
||||||
instance Ord Name where
|
deriving stock instance Ord Defs
|
||||||
compare = coerce compareValue
|
deriving stock instance Eq Defs
|
||||||
deriving stock instance Eq Name
|
deriving stock instance Generic Defs
|
||||||
deriving newtype instance ToJSON Name
|
instance ToJSON Defs where
|
||||||
deriving newtype instance FromJSON Name
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
|
||||||
|
instance FromJSON Defs where
|
||||||
|
parseJSON = withArray "Defs" $ \case
|
||||||
|
[Aeson.String "defs", ctxt, atom, args, begin]
|
||||||
|
-> Defs
|
||||||
|
<$> parseJSON ctxt
|
||||||
|
<*> parseJSON atom
|
||||||
|
<*> parseJSON args
|
||||||
|
<*> parseMaybe begin
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
compareValue :: Aeson.Value -> Aeson.Value -> Ordering
|
compareValue :: Aeson.Value -> Aeson.Value -> Ordering
|
||||||
compareValue v0 v1 = case (v0, v1) of
|
compareValue v0 v1 = case (v0, v1) of
|
||||||
-- This case is buggy:
|
-- This case is buggy:
|
||||||
(Object o0, Object o1) -> compare (fst <$> toList o0) (fst <$> toList o1)
|
(Object o0, Object o1) -> compare (fst <$> toList o0) (fst <$> toList o1)
|
||||||
(Array a0, Array a1) -> foldMap (uncurry compareValue) $ zip (toList a0) (toList a1)
|
(Aeson.Array a0, Aeson.Array a1) -> foldMap (uncurry compareValue) $ zip (toList a0) (toList a1)
|
||||||
(String s0, String s1) -> compare s0 s1
|
(Aeson.String s0, Aeson.String s1) -> compare s0 s1
|
||||||
(Number n0, Number n1) -> compare n0 n1
|
(Number n0, Number n1) -> compare n0 n1
|
||||||
(Bool b0, Bool b1) -> compare b0 b1
|
(Bool b0, Bool b1) -> compare b0 b1
|
||||||
(Null, Null) -> EQ
|
(Null, Null) -> EQ
|
||||||
|
@ -339,8 +387,8 @@ compareValue v0 v1 = case (v0, v1) of
|
||||||
cons :: Aeson.Value -> Word8
|
cons :: Aeson.Value -> Word8
|
||||||
cons = \case
|
cons = \case
|
||||||
Object{} -> 0
|
Object{} -> 0
|
||||||
Array{} -> 1
|
Aeson.Array{} -> 1
|
||||||
String{} -> 2
|
Aeson.String{} -> 2
|
||||||
Number{} -> 3
|
Number{} -> 3
|
||||||
Bool{} -> 4
|
Bool{} -> 4
|
||||||
Null{} -> 5
|
Null{} -> 5
|
||||||
|
@ -355,5 +403,113 @@ instance ToJSON Sym where
|
||||||
toEncoding = Aeson.genericToEncoding aesonOptions
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
instance FromJSON Sym where
|
instance FromJSON Sym where
|
||||||
parseJSON = withArray "Sym" $ \case
|
parseJSON = withArray "Sym" $ \case
|
||||||
[String "sym", atom] -> Sym <$> parseJSON atom
|
[Aeson.String "sym", atom] -> Sym <$> parseJSON atom
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
newtype String = String Text
|
||||||
|
|
||||||
|
deriving stock instance Show String
|
||||||
|
deriving newtype instance Ord String
|
||||||
|
deriving stock instance Eq String
|
||||||
|
deriving stock instance Generic String
|
||||||
|
deriving newtype instance ToJSON String
|
||||||
|
deriving newtype instance FromJSON String
|
||||||
|
newtype Str = Str String
|
||||||
|
|
||||||
|
deriving stock instance Show Str
|
||||||
|
deriving newtype instance Ord Str
|
||||||
|
deriving stock instance Eq Str
|
||||||
|
deriving stock instance Generic Str
|
||||||
|
instance ToJSON Str where
|
||||||
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
instance FromJSON Str where
|
||||||
|
parseJSON = withArray "Str" $ \case
|
||||||
|
[Aeson.String "str", atom] -> Str <$> parseJSON atom
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
data Lvasgn = Lvasgn
|
||||||
|
{ atom :: Atom
|
||||||
|
, statement :: Statement
|
||||||
|
}
|
||||||
|
|
||||||
|
deriving stock instance Show Lvasgn
|
||||||
|
deriving stock instance Ord Lvasgn
|
||||||
|
deriving stock instance Eq Lvasgn
|
||||||
|
deriving stock instance Generic Lvasgn
|
||||||
|
instance ToJSON Lvasgn where
|
||||||
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
instance FromJSON Lvasgn where
|
||||||
|
parseJSON = withArray "Lvasgn" $ \case
|
||||||
|
[Aeson.String "lvasgn", atom, statement] -> Lvasgn <$> parseJSON atom <*> parseJSON statement
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
data Lvar = Lvar
|
||||||
|
{ atom :: Atom
|
||||||
|
}
|
||||||
|
|
||||||
|
deriving stock instance Show Lvar
|
||||||
|
deriving stock instance Ord Lvar
|
||||||
|
deriving stock instance Eq Lvar
|
||||||
|
deriving stock instance Generic Lvar
|
||||||
|
instance ToJSON Lvar where
|
||||||
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
instance FromJSON Lvar where
|
||||||
|
parseJSON = withArray "Lvar" $ \case
|
||||||
|
[Aeson.String "lvar", atom] -> Lvar <$> parseJSON atom
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
data Ivar = Ivar
|
||||||
|
{ atom :: Atom
|
||||||
|
}
|
||||||
|
|
||||||
|
deriving stock instance Show Ivar
|
||||||
|
deriving stock instance Ord Ivar
|
||||||
|
deriving stock instance Eq Ivar
|
||||||
|
deriving stock instance Generic Ivar
|
||||||
|
instance ToJSON Ivar where
|
||||||
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
instance FromJSON Ivar where
|
||||||
|
parseJSON = withArray "Ivar" $ \case
|
||||||
|
[Aeson.String "ivar", atom] -> Ivar <$> parseJSON atom
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
data Self = Self
|
||||||
|
|
||||||
|
deriving stock instance Show Self
|
||||||
|
deriving stock instance Ord Self
|
||||||
|
deriving stock instance Eq Self
|
||||||
|
deriving stock instance Generic Self
|
||||||
|
instance ToJSON Self where
|
||||||
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
instance FromJSON Self where
|
||||||
|
parseJSON = withArray "Self" $ \case
|
||||||
|
[Aeson.String "self"] -> pure Self
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
|
||||||
|
data Cbase = Cbase
|
||||||
|
|
||||||
|
deriving stock instance Show Cbase
|
||||||
|
deriving stock instance Ord Cbase
|
||||||
|
deriving stock instance Eq Cbase
|
||||||
|
deriving stock instance Generic Cbase
|
||||||
|
instance ToJSON Cbase where
|
||||||
|
toEncoding = Aeson.genericToEncoding aesonOptions
|
||||||
|
instance FromJSON Cbase where
|
||||||
|
parseJSON = withArray "Cbase" $ \case
|
||||||
|
[Aeson.String "cbase"] -> pure Cbase
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
|
||||||
|
data Nil = Nil
|
||||||
|
|
||||||
|
deriving stock instance Show Nil
|
||||||
|
deriving stock instance Ord Nil
|
||||||
|
deriving stock instance Eq Nil
|
||||||
|
deriving stock instance Generic Nil
|
||||||
|
instance ToJSON Nil where
|
||||||
|
toJSON = pure Aeson.Null
|
||||||
|
instance FromJSON Nil where
|
||||||
|
parseJSON = \case
|
||||||
|
Aeson.Null -> pure Nil
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
{-# LANGUAGE DuplicateRecordFields, OverloadedLists, InstanceSigs #-}
|
{-# LANGUAGE DuplicateRecordFields, OverloadedLists, InstanceSigs #-}
|
||||||
-- {-# OPTIONS_GHC -Wall #-}
|
{-# OPTIONS_GHC -Wall #-}
|
||||||
module Rubyhs.References
|
module Rubyhs.References
|
||||||
( References(entries)
|
( References(entries)
|
||||||
, Entry(..)
|
|
||||||
, FQN(..)
|
, FQN(..)
|
||||||
, references
|
, references
|
||||||
, Env(..)
|
, Env(..)
|
||||||
, Result(..)
|
, Result(..)
|
||||||
, Namespace(..)
|
|
||||||
, Context(..)
|
, Context(..)
|
||||||
, graph
|
, graph
|
||||||
, prettyContext
|
, prettyContext
|
||||||
|
@ -15,7 +13,7 @@ module Rubyhs.References
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Frelude
|
import Frelude
|
||||||
import Data.Language.Ruby hiding (Namespace)
|
-- import Data.Language.Ruby hiding (context)
|
||||||
import qualified Data.Language.Ruby as Ruby
|
import qualified Data.Language.Ruby as Ruby
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
@ -34,18 +32,13 @@ span (g, f, _) = fmap ((\(x, _, _) -> x) . f) <$> Graph.dff g
|
||||||
|
|
||||||
type G node key = (Graph, Vertex -> (node, key, [key]), key -> Maybe Vertex)
|
type G node key = (Graph, Vertex -> (node, key, [key]), key -> Maybe Vertex)
|
||||||
|
|
||||||
graph :: Begin -> Forest Node
|
graph :: Ruby.Begin -> Forest Node
|
||||||
graph b = span $ Graph.graphFromEdges $ go <$> toList ys
|
graph b = span $ Graph.graphFromEdges $ go <$> toList ys
|
||||||
where
|
where
|
||||||
go :: (Node, Set Node) -> (Node, Text, [Text])
|
go :: (Node, Set Node) -> (Node, Text, [Text])
|
||||||
go (x, xs) = (x, prettyContext x, prettyContext <$> toList xs)
|
go (x, xs) = (x, prettyContext x, prettyContext <$> toList xs)
|
||||||
Result ys = references b
|
Result ys = references b
|
||||||
|
|
||||||
data Entry a = Entry
|
|
||||||
{ node :: a
|
|
||||||
, fqn :: FQN
|
|
||||||
}
|
|
||||||
|
|
||||||
newtype Namespace = Namespace [Text]
|
newtype Namespace = Namespace [Text]
|
||||||
deriving stock instance Show Namespace
|
deriving stock instance Show Namespace
|
||||||
deriving stock instance Eq Namespace
|
deriving stock instance Eq Namespace
|
||||||
|
@ -68,7 +61,7 @@ data FQN = FQN
|
||||||
, name :: Text
|
, name :: Text
|
||||||
}
|
}
|
||||||
|
|
||||||
data Node = NodeFunction FQN | NodeModule Namespace
|
data Node = NodeDef FQN | NodeModule Namespace
|
||||||
|
|
||||||
deriving stock instance Show Node
|
deriving stock instance Show Node
|
||||||
deriving stock instance Eq Node
|
deriving stock instance Eq Node
|
||||||
|
@ -76,7 +69,7 @@ deriving stock instance Ord Node
|
||||||
|
|
||||||
instance ToJSON Node where
|
instance ToJSON Node where
|
||||||
toJSON = \case
|
toJSON = \case
|
||||||
NodeFunction q -> Aeson.toJSON q
|
NodeDef q -> Aeson.toJSON q
|
||||||
NodeModule m -> Aeson.toJSON m
|
NodeModule m -> Aeson.toJSON m
|
||||||
|
|
||||||
deriving stock instance Show FQN
|
deriving stock instance Show FQN
|
||||||
|
@ -101,6 +94,13 @@ newtype Context = Context Node
|
||||||
deriving stock instance Eq Context
|
deriving stock instance Eq Context
|
||||||
deriving stock instance Ord Context
|
deriving stock instance Ord Context
|
||||||
deriving newtype instance ToJSON Context
|
deriving newtype instance ToJSON Context
|
||||||
|
-- HACK: Not really a semigroup as is evident from the implementation.
|
||||||
|
instance Semigroup Context where
|
||||||
|
Context c0 <> Context c1 = case (c0, c1) of
|
||||||
|
(NodeModule n0, NodeModule n1) -> Context $ NodeModule $ n0 <> n1
|
||||||
|
(NodeModule n0, NodeDef (FQN n1 f)) -> Context $ NodeDef $ FQN (n0 <> n1) f
|
||||||
|
(NodeDef{}, NodeModule{}) -> error "Cannot append module to function context."
|
||||||
|
(NodeDef{}, NodeDef{}) -> error "Cannot append function to function context."
|
||||||
|
|
||||||
class Monad m => MyMonad (m :: Type -> Type) where
|
class Monad m => MyMonad (m :: Type -> Type) where
|
||||||
declaration :: Node -> m ()
|
declaration :: Node -> m ()
|
||||||
|
@ -123,7 +123,7 @@ instance ToJSON Result where
|
||||||
|
|
||||||
prettyContext :: Node -> Text
|
prettyContext :: Node -> Text
|
||||||
prettyContext = \case
|
prettyContext = \case
|
||||||
NodeFunction fun -> prettyFQN fun
|
NodeDef fun -> prettyFQN fun
|
||||||
NodeModule ns -> showNamespace ns
|
NodeModule ns -> showNamespace ns
|
||||||
|
|
||||||
instance MyMonad (State Env) where
|
instance MyMonad (State Env) where
|
||||||
|
@ -137,13 +137,10 @@ instance MyMonad (State Env) where
|
||||||
go env@Env{applications}
|
go env@Env{applications}
|
||||||
= env { applications = Map.insertWith mappend c (Set.singleton n) applications }
|
= env { applications = Map.insertWith mappend c (Set.singleton n) applications }
|
||||||
modify go
|
modify go
|
||||||
getContext = gets context
|
getContext = gets Rubyhs.References.context
|
||||||
writeContext q = modify go
|
writeContext q = modify go
|
||||||
where
|
where
|
||||||
go env = env { context = q }
|
go env = env { Rubyhs.References.context = q }
|
||||||
|
|
||||||
updateContext :: MyMonad m => (Context -> Context) -> m ()
|
|
||||||
updateContext f = getContext >>= \c -> writeContext (f c)
|
|
||||||
|
|
||||||
locally :: MyMonad m => m a -> m a
|
locally :: MyMonad m => m a -> m a
|
||||||
locally act = do
|
locally act = do
|
||||||
|
@ -152,128 +149,135 @@ locally act = do
|
||||||
writeContext old
|
writeContext old
|
||||||
pure res
|
pure res
|
||||||
|
|
||||||
appendToContext :: MyMonad m => Name -> m ()
|
|
||||||
appendToContext n = updateContext go
|
|
||||||
where
|
|
||||||
go (Context (NodeModule q)) = Context $ NodeModule $ name2ns n <> q
|
|
||||||
go (Context NodeFunction{}) = error "Cannot append module to context in function context"
|
|
||||||
|
|
||||||
name2ns :: Name -> Namespace
|
|
||||||
name2ns (Name o) = go o
|
|
||||||
where
|
|
||||||
go :: Aeson.Value -> Namespace
|
|
||||||
go = \case
|
|
||||||
Aeson.Array [Aeson.String "const", x, Aeson.String s] -> case x of
|
|
||||||
Aeson.Null -> [s]
|
|
||||||
_ -> go x <> [s]
|
|
||||||
_ -> error $ show o
|
|
||||||
|
|
||||||
class References a where
|
class References a where
|
||||||
entries :: MyMonad m => a -> m ()
|
entries :: MyMonad m => a -> m ()
|
||||||
|
|
||||||
references :: Begin -> Result
|
references :: Ruby.Begin -> Result
|
||||||
references q = Result $ Map.unionWith mappend applications declarations'
|
references q = Result $ Map.unionWith mappend applications declarations'
|
||||||
where
|
where
|
||||||
Env{declarations,applications} = execState (entries @_ @(State Env) q) emptyEnv
|
Env{declarations,applications} = execState (entries @_ @(State Env) q) emptyEnv
|
||||||
emptyEnv = Env mempty mempty (Context $ NodeModule mempty)
|
emptyEnv = Env mempty mempty (Context $ NodeModule mempty)
|
||||||
declarations' = fromList $ (\x -> (x, mempty)) <$> toList declarations
|
declarations' = fromList $ (\x -> (x, mempty)) <$> toList declarations
|
||||||
|
|
||||||
instance References Begin where
|
instance References Ruby.Begin where
|
||||||
entries :: forall m . MyMonad m => Begin -> m ()
|
entries :: forall m . MyMonad m => Ruby.Begin -> m ()
|
||||||
entries (Begin defs) = traverse_ (locally . entries) defs
|
entries (Ruby.Begin defs) = traverse_ (locally . entries) defs
|
||||||
|
|
||||||
instance References Statement where
|
instance References Ruby.Statement where
|
||||||
entries = \case
|
entries = \case
|
||||||
StmtModule m -> entries m
|
Ruby.StmtModule m -> entries m
|
||||||
StmtFunction f -> entries f
|
Ruby.StmtDef f -> entries f
|
||||||
StmtSend s -> entries s
|
Ruby.StmtDefs f -> entries f
|
||||||
StmtConst c -> entries c
|
Ruby.StmtSend s -> entries s
|
||||||
StmtBlock b -> entries b
|
Ruby.StmtConst c -> entries c
|
||||||
StmtCasgn c -> entries c
|
Ruby.StmtBlock b -> entries b
|
||||||
StmtArray a -> entries a
|
Ruby.StmtCasgn c -> entries c
|
||||||
StmtSym s -> entries s
|
Ruby.StmtArray a -> entries a
|
||||||
StmtAnything a -> entries a
|
Ruby.StmtSym s -> entries s
|
||||||
|
Ruby.StmtStr s -> entries s
|
||||||
|
Ruby.StmtLvasgn a -> entries a
|
||||||
|
Ruby.StmtLvar a -> entries a
|
||||||
|
Ruby.StmtIvar a -> entries a
|
||||||
|
Ruby.StmtSelf s -> entries s
|
||||||
|
Ruby.StmtCbase s -> entries s
|
||||||
|
Ruby.StmtNil n -> entries n
|
||||||
|
Ruby.StmtAnything a -> entries a
|
||||||
|
|
||||||
instance References Ruby.Block where
|
instance References Ruby.Block where
|
||||||
entries Block{send,args,begin} = do
|
entries Ruby.Block{send,args,begin} = do
|
||||||
entries send
|
entries send
|
||||||
entries args
|
entries args
|
||||||
entries begin
|
entries begin
|
||||||
instance References Ruby.RArgs where
|
instance References Ruby.Args where
|
||||||
entries = const $ pure ()
|
entries = const $ pure ()
|
||||||
-- TODO: We have to make a "declaration" for the constant here as
|
-- TODO: We have to make a "declaration" for the constant here as
|
||||||
-- well!
|
-- well!
|
||||||
instance References Ruby.Casgn where
|
instance References Ruby.Casgn where
|
||||||
entries Casgn{name, statement} = entries statement
|
entries Ruby.Casgn{rhs} = entries rhs
|
||||||
instance References Ruby.Sym where
|
instance References Ruby.Sym where
|
||||||
entries _ = pure ()
|
entries _ = pure ()
|
||||||
instance References Ruby.RArray where
|
instance References Ruby.Str where
|
||||||
entries RArray{statements} = traverse_ entries statements
|
entries _ = pure ()
|
||||||
|
instance References Ruby.Lvasgn where
|
||||||
|
entries _ = pure ()
|
||||||
|
instance References Ruby.Lvar where
|
||||||
|
entries _ = pure ()
|
||||||
|
instance References Ruby.Ivar where
|
||||||
|
entries _ = pure ()
|
||||||
|
instance References Ruby.Self where
|
||||||
|
entries _ = pure ()
|
||||||
|
instance References Ruby.Cbase where
|
||||||
|
entries _ = pure ()
|
||||||
|
instance References Ruby.Nil where
|
||||||
|
entries _ = pure ()
|
||||||
|
instance References Ruby.Array where
|
||||||
|
entries Ruby.Array{statements} = traverse_ entries statements
|
||||||
instance References Ruby.Anything where
|
instance References Ruby.Anything where
|
||||||
entries = const $ pure ()
|
entries = const $ pure ()
|
||||||
|
|
||||||
instance References Ruby.Namespace where
|
instance References Ruby.Const where
|
||||||
entries (Ruby.Namespace xs) = do
|
entries con = application $ NodeModule $ constToNamespace con
|
||||||
Context c <- getContext
|
|
||||||
let
|
|
||||||
ctxt = case c of
|
|
||||||
NodeFunction FQN{namespace} -> namespace
|
|
||||||
NodeModule namespace -> namespace
|
|
||||||
-- TODO Hacky:
|
|
||||||
ns = Namespace ((\(Name (Aeson.String t)) -> t) <$> xs)
|
|
||||||
-- TODO: Broken
|
|
||||||
-- application c (NodeModule $ ctxt `onTop` ns)
|
|
||||||
application (NodeModule $ ns)
|
|
||||||
|
|
||||||
instance References Module where
|
updateContext :: MyMonad m => (Context -> Context) -> m ()
|
||||||
entries Module{name, begin} = do
|
updateContext f = getContext >>= \c -> writeContext (f c)
|
||||||
appendToContext name
|
|
||||||
|
instance References Ruby.Module where
|
||||||
|
entries Ruby.Module{name, begin} = do
|
||||||
|
updateContext $ (<>) $ Context $ NodeModule $ constToNamespace name
|
||||||
c <- getContext >>= \case
|
c <- getContext >>= \case
|
||||||
Context (NodeModule c) -> pure c
|
Context (NodeModule c) -> pure c
|
||||||
_ -> error "..."
|
_ -> error "..."
|
||||||
declaration $ NodeModule c
|
declaration $ NodeModule c
|
||||||
entries begin
|
entries begin
|
||||||
|
|
||||||
nameToNode :: MyMonad m => Name -> m Node
|
atomToNode :: MyMonad m => Ruby.Atom -> m Node
|
||||||
nameToNode name = do
|
atomToNode (Ruby.Atom name) = do
|
||||||
namespace <- getContext >>= \case
|
namespace <- getContext >>= \case
|
||||||
Context (NodeModule c) -> pure c
|
Context (NodeModule c) -> pure c
|
||||||
Context NodeFunction{} -> error "Cannot have a function declaration in a function context"
|
-- We could allow this and just say that the function defined in
|
||||||
pure $ NodeFunction $ qual namespace name
|
-- another function sits in the same context as the surrounding
|
||||||
|
-- function.
|
||||||
|
Context NodeDef{} -> error "Cannot have a function declaration in a function context"
|
||||||
|
pure $ NodeDef $ FQN namespace name
|
||||||
|
|
||||||
instance References Function where
|
instance References Ruby.Def where
|
||||||
entries Function{name, begin} = do
|
entries Ruby.Def{atom, begin} = do
|
||||||
node <- nameToNode name
|
node <- atomToNode atom
|
||||||
declaration node
|
declaration node
|
||||||
locally $ do
|
locally $ do
|
||||||
writeContext (Context node)
|
writeContext (Context node)
|
||||||
entries begin
|
entries begin
|
||||||
|
|
||||||
qual :: Namespace -> Name -> FQN
|
instance References Ruby.Defs where
|
||||||
qual namespace (Name o) = case o of
|
-- TODO: The field `context` is also relevant here!
|
||||||
Aeson.String name -> FQN { namespace , name }
|
entries Ruby.Defs{atom, begin}
|
||||||
_ -> error $ show o
|
= entries $ Ruby.Def{atom,begin,args=error "hack"}
|
||||||
|
|
||||||
|
qual :: Namespace -> Ruby.Atom -> FQN
|
||||||
|
qual namespace (Ruby.Atom name) = FQN { namespace , name }
|
||||||
|
|
||||||
onTop' :: Eq a => [a] -> [a] -> [a]
|
instance References Ruby.Send where
|
||||||
onTop' [] y = y
|
entries Ruby.Send{context, atom, args} = do
|
||||||
onTop' x [] = x
|
application $ NodeDef $ qual (statementToNamespace context) atom
|
||||||
onTop' (x:xss) ys@(y:yss) = if
|
traverse_ entries args
|
||||||
| x == y -> pure x <> yss
|
|
||||||
| otherwise -> pure x <> xss `onTop'` ys
|
|
||||||
|
|
||||||
onTop :: Namespace -> Namespace -> Namespace
|
statementToNamespace :: Ruby.Statement -> Namespace
|
||||||
onTop (Namespace xs) (Namespace ys) = Namespace $ reverse $ reverse xs `onTop'` reverse ys
|
statementToNamespace = go mempty
|
||||||
|
where
|
||||||
|
go acc = \case
|
||||||
|
Ruby.StmtConst c -> acc <> constToNamespace c
|
||||||
|
-- The nil-case and cbase-case should produce different results,
|
||||||
|
-- surely. `Namespace` may not be a good representation.
|
||||||
|
Ruby.StmtNil{} -> acc
|
||||||
|
Ruby.StmtCbase{} -> acc
|
||||||
|
-- The send-, ivar- and lvar- case cannot be handled because of the way
|
||||||
|
-- we've defined `Namespace`.
|
||||||
|
Ruby.StmtSend{} -> acc
|
||||||
|
Ruby.StmtIvar{} -> acc
|
||||||
|
Ruby.StmtLvar{} -> acc
|
||||||
|
_ -> error "Can only build namespaces from sequences of `const` statements"
|
||||||
|
|
||||||
instance References Send where
|
constToNamespace :: Ruby.Const -> Namespace
|
||||||
entries Send{namespace, name} = do
|
constToNamespace Ruby.Const{context, atom} = statementToNamespace context <> [k]
|
||||||
-- TODO: Broken
|
where
|
||||||
-- application c $ NodeFunction $ qual (ctxt `onTop` fromNS namespace) name
|
Ruby.Atom k = atom
|
||||||
application $ NodeFunction $ qual (fromNS namespace) name
|
|
||||||
where
|
|
||||||
fromNS :: Ruby.Namespace -> Namespace
|
|
||||||
fromNS (Ruby.Namespace l) = Namespace $ go <$> l
|
|
||||||
go :: Name -> Text
|
|
||||||
go (Name o) = case o of
|
|
||||||
Aeson.String s -> s
|
|
||||||
_ -> error $ show o
|
|
||||||
|
|
Loading…
Reference in a new issue