Let there be light
This commit is contained in:
commit
d66b93997f
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.stack-work/
|
||||||
|
rubyhs.cabal
|
||||||
|
*~
|
3
ChangeLog.md
Normal file
3
ChangeLog.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Changelog for rubyhs
|
||||||
|
|
||||||
|
## Unreleased changes
|
30
LICENSE
Normal file
30
LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Copyright Frederik Hanghøj Iversen (c) 2019
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of Frederik Hanghøj Iversen nor the names of other
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
4
Setup.hs
Normal file
4
Setup.hs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import Distribution.Simple
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = defaultMain
|
7
app/Main.hs
Normal file
7
app/Main.hs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module Main where
|
||||||
|
|
||||||
|
import Frelude
|
||||||
|
import qualified Rubyhs
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = Rubyhs.main
|
77
package.yaml
Normal file
77
package.yaml
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
name: rubyhs
|
||||||
|
version: 0.1.0.0
|
||||||
|
github: "fredefox/rubyhs"
|
||||||
|
license: BSD3
|
||||||
|
author: "Frederik Hanghøj Iversen"
|
||||||
|
maintainer: "fhi.1990@gmail.com"
|
||||||
|
copyright: "2019 Frederik Hanghøj Iversen"
|
||||||
|
|
||||||
|
extra-source-files:
|
||||||
|
- README.md
|
||||||
|
- ChangeLog.md
|
||||||
|
|
||||||
|
# Metadata used when publishing your package
|
||||||
|
# synopsis: Short description of your package
|
||||||
|
# category: Web
|
||||||
|
|
||||||
|
# To avoid duplicated efforts in documentation and dealing with the
|
||||||
|
# complications of embedding Haddock markup inside cabal files, it is
|
||||||
|
# common to point users to the README.md file.
|
||||||
|
description:
|
||||||
|
Please see the README on GitHub at <https://github.com/fredefox/rubyhs#readme>
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- base >= 4.7 && < 5
|
||||||
|
- process
|
||||||
|
- aeson
|
||||||
|
- vector
|
||||||
|
- bytestring
|
||||||
|
- frelude
|
||||||
|
|
||||||
|
default-extensions:
|
||||||
|
- ConstraintKinds
|
||||||
|
- DeriveGeneric
|
||||||
|
- FlexibleContexts
|
||||||
|
- FlexibleInstances
|
||||||
|
- GADTs
|
||||||
|
- GeneralizedNewtypeDeriving
|
||||||
|
- LambdaCase
|
||||||
|
- NamedWildCards
|
||||||
|
- OverloadedStrings
|
||||||
|
- ScopedTypeVariables
|
||||||
|
- StandaloneDeriving
|
||||||
|
- TupleSections
|
||||||
|
- TypeApplications
|
||||||
|
- TypeFamilies
|
||||||
|
- TypeSynonymInstances
|
||||||
|
- UnicodeSyntax
|
||||||
|
- ViewPatterns
|
||||||
|
- DerivingStrategies
|
||||||
|
- EmptyCase
|
||||||
|
- NoImplicitPrelude
|
||||||
|
- DeriveAnyClass
|
||||||
|
|
||||||
|
library:
|
||||||
|
source-dirs: src
|
||||||
|
|
||||||
|
executables:
|
||||||
|
rubyhs:
|
||||||
|
main: Main.hs
|
||||||
|
source-dirs: app
|
||||||
|
ghc-options:
|
||||||
|
- -threaded
|
||||||
|
- -rtsopts
|
||||||
|
- -with-rtsopts=-N
|
||||||
|
dependencies:
|
||||||
|
- rubyhs
|
||||||
|
|
||||||
|
tests:
|
||||||
|
test:
|
||||||
|
main: Spec.hs
|
||||||
|
source-dirs: test
|
||||||
|
ghc-options:
|
||||||
|
- -threaded
|
||||||
|
- -rtsopts
|
||||||
|
- -with-rtsopts=-N
|
||||||
|
dependencies:
|
||||||
|
- rubyhs
|
2
ruby/fun.rb
Normal file
2
ruby/fun.rb
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
def f
|
||||||
|
end
|
23
ruby/test.rb
Normal file
23
ruby/test.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
module M
|
||||||
|
def f
|
||||||
|
end
|
||||||
|
|
||||||
|
def g
|
||||||
|
|
||||||
|
f(2)
|
||||||
|
h(2, a: 'a')
|
||||||
|
h(2, a: :a)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# class C
|
||||||
|
# end
|
||||||
|
|
||||||
|
module K
|
||||||
|
end
|
||||||
|
|
||||||
|
f(2)
|
||||||
|
h(2, a: 'a')
|
||||||
|
h(2, a: :a)
|
||||||
|
|
140
src/Rubyhs.hs
Normal file
140
src/Rubyhs.hs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
{-# LANGUAGE DuplicateRecordFields, OverloadedLists #-}
|
||||||
|
{-# OPTIONS_GHC -Wall #-}
|
||||||
|
module Rubyhs (main) where
|
||||||
|
|
||||||
|
import Frelude
|
||||||
|
import System.Process
|
||||||
|
import System.Environment
|
||||||
|
import Data.Foldable (traverse_)
|
||||||
|
import Data.Aeson (parseJSON, Value(String), withArray, eitherDecode, encode)
|
||||||
|
import Data.Aeson.Types
|
||||||
|
import Data.ByteString.Lazy (ByteString)
|
||||||
|
import qualified Data.ByteString.Lazy.Char8 as ByteString
|
||||||
|
import Control.Monad.Fail (MonadFail)
|
||||||
|
import qualified Data.Vector as Vector
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = getArgs >>= traverse_ run
|
||||||
|
|
||||||
|
kebabCase :: String -> String
|
||||||
|
kebabCase = camelTo2 '-'
|
||||||
|
|
||||||
|
newtype Block = Block [Definition]
|
||||||
|
|
||||||
|
opts :: Options
|
||||||
|
opts = defaultOptions { sumEncoding = ObjectWithSingleField, constructorTagModifier = kebabCase }
|
||||||
|
|
||||||
|
deriving stock instance Show Block
|
||||||
|
deriving stock instance Generic Block
|
||||||
|
instance ToJSON Block where
|
||||||
|
toEncoding = genericToEncoding opts
|
||||||
|
|
||||||
|
instance FromJSON Block where
|
||||||
|
parseJSON = withArray "Block" $ \as -> case Vector.toList as of
|
||||||
|
(String "begin":xs) -> Block <$> traverse parseJSON xs
|
||||||
|
_ -> Block . pure <$> parseJSON (Array as)
|
||||||
|
|
||||||
|
data Definition = DefModule Module | DefFunction Function | DefSend Send
|
||||||
|
|
||||||
|
deriving stock instance Show Definition
|
||||||
|
deriving stock instance Generic Definition
|
||||||
|
instance ToJSON Definition where
|
||||||
|
toEncoding = genericToEncoding ( opts { constructorTagModifier = go })
|
||||||
|
where
|
||||||
|
go = \case
|
||||||
|
"DefModule" -> "module"
|
||||||
|
"DefFunction" -> "function"
|
||||||
|
"DefSend" -> "send"
|
||||||
|
x -> x
|
||||||
|
|
||||||
|
instance FromJSON Definition where
|
||||||
|
parseJSON val
|
||||||
|
= (DefModule <$> parseJSON val)
|
||||||
|
<|> (DefFunction <$> parseJSON val)
|
||||||
|
<|> (DefSend <$> parseJSON val)
|
||||||
|
|
||||||
|
data Send = Send
|
||||||
|
{ args :: Args
|
||||||
|
, name :: Name
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deriving stock instance Show Send
|
||||||
|
deriving stock instance Generic Send
|
||||||
|
instance ToJSON Send where
|
||||||
|
toEncoding = genericToEncoding opts
|
||||||
|
|
||||||
|
instance FromJSON Send where
|
||||||
|
parseJSON = withArray "Send" $ \ as -> case Vector.toList as of
|
||||||
|
(String "send" : _ : name : args) -> Send <$> parseJSON (Array $ Vector.fromList args) <*> parseJSON name
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
data Module = Module
|
||||||
|
{ name :: Name
|
||||||
|
, block :: Block
|
||||||
|
}
|
||||||
|
|
||||||
|
deriving stock instance Show Module
|
||||||
|
deriving stock instance Generic Module
|
||||||
|
instance ToJSON Module where
|
||||||
|
toEncoding = genericToEncoding opts
|
||||||
|
|
||||||
|
instance FromJSON Module where
|
||||||
|
parseJSON = withArray "Module" $ \case
|
||||||
|
[String "module", name, block] -> Module <$> parseJSON name <*> parseMaybeBlock block
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
parseMaybeBlock :: Value -> Parser Block
|
||||||
|
parseMaybeBlock = \case
|
||||||
|
Null -> pure (Block mempty)
|
||||||
|
x -> parseJSON x
|
||||||
|
|
||||||
|
data Function = Function
|
||||||
|
{ name :: Name
|
||||||
|
, args :: Args
|
||||||
|
, block :: Block
|
||||||
|
}
|
||||||
|
|
||||||
|
deriving stock instance Show Function
|
||||||
|
deriving stock instance Generic Function
|
||||||
|
instance ToJSON Function where
|
||||||
|
toEncoding = genericToEncoding opts
|
||||||
|
|
||||||
|
newtype Args = Args Value
|
||||||
|
|
||||||
|
deriving stock instance Show Args
|
||||||
|
deriving stock instance Generic Args
|
||||||
|
instance ToJSON Args where
|
||||||
|
toEncoding = genericToEncoding opts
|
||||||
|
|
||||||
|
instance FromJSON Args where
|
||||||
|
parseJSON = pure . Args
|
||||||
|
|
||||||
|
instance FromJSON Function where
|
||||||
|
parseJSON = withArray "Function" $ \case
|
||||||
|
[String "def", name, args, block] -> Function <$> parseJSON name <*> parseJSON args <*> parseMaybeBlock block
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
newtype Name = Name Value
|
||||||
|
|
||||||
|
deriving stock instance Show Name
|
||||||
|
deriving newtype instance ToJSON Name
|
||||||
|
deriving newtype instance FromJSON Name
|
||||||
|
|
||||||
|
run :: FilePath -> IO ()
|
||||||
|
run p = do
|
||||||
|
json <- runParser p
|
||||||
|
block <- decodeFail @_ @Block $ ByteString.pack json
|
||||||
|
ByteString.putStrLn $ encode block
|
||||||
|
|
||||||
|
decodeFail :: MonadFail m => FromJSON a => ByteString -> m a
|
||||||
|
decodeFail s = case eitherDecode s of
|
||||||
|
Left err -> fail err
|
||||||
|
Right a -> pure a
|
||||||
|
|
||||||
|
runParser :: FilePath -> IO String
|
||||||
|
runParser p = sh "ruby-parse" ["--emit-json", "--25", p]
|
||||||
|
|
||||||
|
sh :: String -> [String] -> IO String
|
||||||
|
sh cmd args = readProcess cmd args mempty
|
||||||
|
|
8
stack.yaml
Normal file
8
stack.yaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
resolver: lts-14.7
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- .
|
||||||
|
|
||||||
|
extra-deps:
|
||||||
|
- git: git@git.data.coop:fredefox/frelude.git
|
||||||
|
commit: 3524ffa4046b45d79192f2722a3d41b35c16f102
|
2
test/Spec.hs
Normal file
2
test/Spec.hs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
main :: IO ()
|
||||||
|
main = putStrLn "Test suite not yet implemented"
|
Loading…
Reference in a new issue