Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quoter #64

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion language-python/language-python.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ Library
array >= 0.4 && < 0.6,
transformers >= 0.3 && < 0.6,
monads-tf == 0.1.*,
utf8-string >= 1 && < 2
utf8-string >= 1 && < 2,
template-haskell >=2.10

build-tools: happy, alex
exposed-modules:
Language.Python.Common
Expand All @@ -45,6 +47,7 @@ Library
Language.Python.Common.PrettyToken
Language.Python.Common.AST
Language.Python.Common.PrettyAST
Language.Python.Common.Quoter
Language.Python.Version3
Language.Python.Version3.Parser
Language.Python.Version3.Lexer
Expand Down
5 changes: 4 additions & 1 deletion language-python/src/Language/Python/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ module Language.Python.Common (
-- * Parse errors
module Language.Python.Common.ParseError,
-- * Pretty printing parse errors
module Language.Python.Common.PrettyParseError -- this export is for Haddock
module Language.Python.Common.PrettyParseError, -- this export is for Haddock
-- * Quasiquoter
module Language.Python.Common.Quoter
) where

import Language.Python.Common.Pretty
Expand All @@ -38,3 +40,4 @@ import Language.Python.Common.PrettyToken ()
import Language.Python.Common.SrcLocation
import Language.Python.Common.PrettyParseError ()
import Language.Python.Common.ParseError
import Language.Python.Common.Quoter
106 changes: 106 additions & 0 deletions language-python/src/Language/Python/Common/Quoter.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
-----------------------------------------------------------------------------
-- |
-- Module : Language.Python.Common.Quoter
-- License : BSD-style
-- Stability : experimental
-- Portability : ghc
--
-- Simple quasiquoters for converting python code into haskell expressions or patterns (it doesn't work for declarations and types).
-- Multi-line python quotations must be left aligned in the file.
-- Examples, that will yield :
-- @
-- binOpExpr = [pyExpr|x+y|]
--
-- [retStmt] = [pyStmt|return z|]
--
-- [py2Print] = [py2] = [py2Stmt|print somelist[1], "Hej there!"|]
--
-- pyMod = [pyModule|
-- import something
--
-- def fun(a,b):
-- c = a+b
-- print(c)
-- |]
-- @
-- Caution: This checks only for syntax of single quotes, not types or scopes or combinations of quotes.
-- For example nothing keeps you from appending py2Print to pyMod. So this can be used to generate code,
-- but checking validity is up to you.
-----------------------------------------------------------------------------

module Language.Python.Common.Quoter (
-- * Quoting python 3.x modules
pyModule,
-- * Quoting python 3.x statements
pyStmt,
-- * Quoting python 3.x expressions
pyExpr,
-- * Quoting python 2.x modules
py2Module,
-- * Quoting python 2.x statements
py2Stmt,
-- * Quoting python 2.x expressions
py2Expr) where

import Language.Python.Version3.Parser as V3
import Language.Python.Version2.Parser as V2

import Language.Python.Common.Token as Token
import Language.Python.Common.ParserMonad ( ParseError)
import Data.Data ( Data )

import Language.Haskell.TH
import Language.Haskell.TH.Quote ( QuasiQuoter(..), dataToExpQ, dataToPatQ )

quoter :: (Data a) => (String -> String -> Either ParseError (a, [Token]))-> QuasiQuoter
quoter parser = QuasiQuoter
{ quoteExp = parseAndExpQuote parser
, quotePat = parseAndPatQuote parser
, quoteDec = error "this quasiquoter does not support declarations"
, quoteType = error "this quasiquoter does not support types"
}


parseAndExpQuote:: (Data a) => (String -> String -> Either ParseError (a, [Token])) -> String -> Q Exp
parseAndExpQuote parser content = do
parseResult <- apply parser "" content
dataToExpQ (const Nothing) parseResult

parseAndPatQuote:: (Data a) => (String -> String -> Either ParseError (a, [Token]))-> String -> Q Pat
parseAndPatQuote parser content = do
parseResult <- apply parser "" content
dataToPatQ (const Nothing) parseResult

apply:: (Monad m, MonadFail m) =>
(String -> String -> Either ParseError (a, [Token]))
-> String -> String -> m a
apply parser name content =
case parser content name of
Left parseError -> fail $ show parseError
Right (subAST, comments) -> return subAST


pyModule :: QuasiQuoter
pyModule = quoter V3.parseModule


pyStmt :: QuasiQuoter
pyStmt = quoter V3.parseStmt


pyExpr:: QuasiQuoter
pyExpr = quoter V3.parseExpr


py2Module :: QuasiQuoter
py2Module = quoter V2.parseModule


py2Stmt :: QuasiQuoter
py2Stmt = quoter V2.parseStmt


py2Expr:: QuasiQuoter
py2Expr = quoter V2.parseExpr


4 changes: 2 additions & 2 deletions language-python/src/Language/Python/Version3.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ module Language.Python.Version3 (
-- * The parser
module Language.Python.Version3.Parser,
-- * The lexer
module Language.Python.Version3.Lexer
module Language.Python.Version3.Lexer
) where

import Language.Python.Version3.Parser
import Language.Python.Version3.Lexer
import Language.Python.Version3.Lexer