1
Fork 0

pretty printer, minor clean ups

clean up some warnings
update the cabal file
add pretty printer
add pretty printing tests
This commit is contained in:
Jake Wheat 2013-12-13 15:05:32 +02:00
parent 52b9f3f4f4
commit e3be820dfb
5 changed files with 157 additions and 76 deletions

View file

@ -2,15 +2,12 @@
> module Parser (parseQueryExpr > module Parser (parseQueryExpr
> ,parseScalarExpr > ,parseScalarExpr
> ,ParseError(..)) where > ,ParseError) where
> import Text.Groom > import Text.Groom
> import Text.Parsec > import Text.Parsec
> import Control.Monad.Identity > import Control.Monad.Identity
> import Control.Applicative hiding (many, (<|>), optional) > import Control.Applicative hiding (many, (<|>), optional)
> import Debug.Trace
> import Data.List
> import Text.Parsec.Expr
> import qualified Language.Haskell.Exts.Syntax as HSE > import qualified Language.Haskell.Exts.Syntax as HSE
> import qualified Language.Haskell.Exts.Fixity as HSE > import qualified Language.Haskell.Exts.Fixity as HSE
> import Data.Maybe > import Data.Maybe
@ -200,9 +197,9 @@ to be.
> tref = choice [try (JoinQueryExpr <$> parens queryExpr) > tref = choice [try (JoinQueryExpr <$> parens queryExpr)
> ,JoinParens <$> parens tref > ,JoinParens <$> parens tref
> ,SimpleTableRef <$> identifierString] > ,SimpleTableRef <$> identifierString]
> >>= optionSuffix join > >>= optionSuffix pjoin
> >>= optionSuffix alias > >>= optionSuffix alias
> join tref0 = > pjoin tref0 =
> choice > choice
> [try (keyword_ "natural") *> keyword_ "inner" > [try (keyword_ "natural") *> keyword_ "inner"
> *> conditionlessSuffix tref0 Inner (Just JoinNatural) > *> conditionlessSuffix tref0 Inner (Just JoinNatural)
@ -217,7 +214,7 @@ to be.
> ,try (keyword_ "cross") > ,try (keyword_ "cross")
> *> conditionlessSuffix tref0 Cross Nothing > *> conditionlessSuffix tref0 Cross Nothing
> ] > ]
> >>= optionSuffix join > >>= optionSuffix pjoin
> outerJoinSuffix tref0 jt = > outerJoinSuffix tref0 jt =
> optional (keyword_ "outer") *> conditionSuffix tref0 jt > optional (keyword_ "outer") *> conditionSuffix tref0 jt
> conditionSuffix tref0 jt = > conditionSuffix tref0 jt =

View file

@ -2,12 +2,118 @@
This is the pretty printer code which takes AST values and turns them This is the pretty printer code which takes AST values and turns them
back into SQL source text. It attempts to format the output nicely. back into SQL source text. It attempts to format the output nicely.
> module Pretty (pretty, prettyScalarExpr) where > module Pretty (prettyQueryExpr, prettyScalarExpr) where
> import Syntax > import Syntax
> import Text.PrettyPrint
> import Data.Maybe
> pretty :: QueryExpr -> String > prettyQueryExpr :: QueryExpr -> String
> pretty = undefined > prettyQueryExpr = render . queryExpr
> prettyScalarExpr :: ScalarExpr -> String > prettyScalarExpr :: ScalarExpr -> String
> prettyScalarExpr = undefined > prettyScalarExpr = render . scalarExpr
= scalar expressions
> scalarExpr :: ScalarExpr -> Doc
> scalarExpr (Literal s) = quotes $ text s
> scalarExpr (Identifier i) = text i
> scalarExpr (Identifier2 q i) = text q <> text "." <> text i
> scalarExpr Star = text "*"
> scalarExpr (Star2 q) = text q <> text "." <> text "*"
> scalarExpr (App f es) = text f <> parens (commaSep (map scalarExpr es))
> scalarExpr (Op f [e]) = text f <+> scalarExpr e
> scalarExpr (Op f [e0,e1]) =
> sep [scalarExpr e0, text f, scalarExpr e1]
> scalarExpr (Op f es) =
> -- TODO: how to handle this? error or either seems poor
> text f <> parens (commaSep (map scalarExpr es))
> scalarExpr (Case t ws els) =
> sep [text "case" <+> (maybe empty scalarExpr t)
> ,nest 4 (sep ((map w ws)
> ++ maybeToList (fmap e els)))
> ,text "end"]
> where
> w (t0,t1) = sep [text "when" <+> scalarExpr t0
> ,text "then" <+> scalarExpr t1]
> e el = text "else" <+> scalarExpr el
> scalarExpr (Parens e) = parens $ scalarExpr e
= query expressions
> queryExpr :: QueryExpr -> Doc
> queryExpr (Select sl fr wh gb hv od) =
> sep [text "select"
> ,nest 4 $ sep [selectList sl]
> ,from fr
> ,whr wh
> ,grpBy gb
> ,having hv
> ,orderBy od]
> selectList :: [(Maybe String, ScalarExpr)] -> Doc
> selectList is = commaSep $ map si is
> where
> si (al,e) = scalarExpr e <+> maybe empty alias al
> alias al = text "as" <+> text al
> from :: [TableRef] -> Doc
> from [] = empty
> from ts =
> sep [text "from"
> ,nest 4 $ commaSep $ map tr ts]
> where
> tr (SimpleTableRef t) = text t
> tr (JoinAlias t a) = tr t <+> text "as" <+> text a
> tr (JoinParens t) = parens $ tr t
> tr (JoinQueryExpr q) = parens $ queryExpr q
> tr (JoinTableRef jt t0 t1 jc) =
> sep [tr t0
> ,joinText jt jc
> ,tr t1
> ,joinCond jc]
> joinText jt jc =
> sep [case jc of
> Just JoinNatural -> text "natural"
> _ -> empty
> ,case jt of
> Inner -> text "inner"
> JLeft -> text "left"
> JRight -> text "right"
> Full -> text "full"
> Cross -> text "cross"
> ,text "join"]
> joinCond (Just (JoinOn e)) = text "on" <+> scalarExpr e
> joinCond (Just (JoinUsing es)) = text "using" <+> parens (commaSep $ map text es)
> joinCond Nothing = empty
> joinCond (Just JoinNatural) = empty
> whr :: Maybe ScalarExpr -> Doc
> whr = maybe empty
> (\w -> sep [text "where"
> ,nest 4 $ scalarExpr w])
> grpBy :: [ScalarExpr] -> Doc
> grpBy [] = empty
> grpBy gs = sep [text "group by"
> ,nest 4 $ commaSep $ map scalarExpr gs]
> having :: Maybe ScalarExpr -> Doc
> having = maybe empty
> (\w -> sep [text "having"
> ,nest 4 $ scalarExpr w])
> orderBy :: [ScalarExpr] -> Doc
> orderBy [] = empty
> orderBy os = sep [text "order by"
> ,nest 4 $ commaSep $ map scalarExpr os]
= utils
> commaSep :: [Doc] -> Doc
> commaSep ds = sep $ punctuate comma ds

19
TODO
View file

@ -1,24 +1,24 @@
add tests
left factor parsing code add tests to cabal
implement pretty printer haddock
reimplement the fixity thing natively
dialect switching dialect switching
fix lexing wrt suffixes
left factor parsing code
reimplement the fixity thing natively
fix lexing wrt suffixes 1/2 done
position annotation position annotation
emacs parse error formatting emacs parse error formatting
haddock
= sql support = sql support
count(*)
decimal literals, split string and number literals decimal literals, split string and number literals
order by directions order by directions
distinct/all distinct/all
@ -59,12 +59,13 @@ group by (), grouping sets(), cube, rollup
lateral lateral
corresponding corresponding
named windows named windows
table, values
cte cte
apply, pivot apply, pivot
full tableref aliases full tableref aliases
collate collate
within group aggregate syntax within group aggregate syntax
try to do full review of sql2003 query syntax try to do full review of sql2003 query syntax
maybe later: other dml maybe later: other dml

View file

@ -1,5 +1,5 @@
> module Tests (testData) where > module Tests (testData, runTests) where
> import Syntax > import Syntax
> import Pretty > import Pretty
@ -239,12 +239,24 @@
> itemToTest (Group nm ts) = > itemToTest (Group nm ts) =
> H.TestLabel nm $ H.TestList $ map itemToTest ts > H.TestLabel nm $ H.TestList $ map itemToTest ts
> itemToTest (TestScalarExpr str expected) = > itemToTest (TestScalarExpr str expected) =
> toTest parseScalarExpr str expected > toTest parseScalarExpr prettyScalarExpr str expected
> itemToTest (TestQueryExpr str expected) = > itemToTest (TestQueryExpr str expected) =
> toTest parseQueryExpr str expected > toTest parseQueryExpr prettyQueryExpr str expected
> toTest parser str expected = H.TestLabel str $ H.TestCase $ do > toTest :: (Eq a, Show a, Show e) =>
> (String -> Maybe (Int,Int) -> String -> Either e a)
> -> (a -> String)
> -> String
> -> a
> -> H.Test
> toTest parser pp str expected = H.TestLabel str $ H.TestCase $ do
> let egot = parser "" Nothing str > let egot = parser "" Nothing str
> case egot of > case egot of
> Left e -> H.assertFailure $ show e > Left e -> H.assertFailure $ show e
> Right got -> H.assertEqual "" expected got > Right got -> do
> H.assertEqual "" expected got
> let str' = pp got
> let egot' = parser "" Nothing str'
> case egot' of
> Left e' -> H.assertFailure $ "pp roundtrip " ++ show e'
> Right got' -> H.assertEqual "pp roundtrip" expected got'

View file

@ -1,70 +1,35 @@
-- Initial simple-sql-parser.cabal generated by cabal init. For further
-- documentation, see http://haskell.org/cabal/users-guide/
-- The name of the package.
name: simple-sql-parser name: simple-sql-parser
-- The package version. See the Haskell package versioning policy (PVP)
-- for standards guiding when and how versions should be incremented.
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
-- PVP summary: +-+------- breaking API changes
-- | | +----- non-breaking API additions
-- | | | +--- code changes with no API change
version: 0.1.0.0 version: 0.1.0.0
-- A short (one-line) description of the package.
synopsis: A parser for SQL queries synopsis: A parser for SQL queries
-- A longer description of the package. description: A parser for SQL queries, using Parsec. Also includes pretty printer. Aims to support most of SQL2003 queries.
-- description:
-- URL for the project homepage or repository. homepage: https://github.com/JakeWheat/simple_sql_parser
homepage: xx
-- The license under which the package is released.
license: BSD3 license: BSD3
-- The file containing the license text.
license-file: LICENSE license-file: LICENSE
-- The package author(s).
author: Jake Wheat author: Jake Wheat
-- An email address to which users can send suggestions, bug reports, and
-- patches.
maintainer: jakewheatmail@gmail.com maintainer: jakewheatmail@gmail.com
copyright: Copyright Jake Wheat 2013
-- A copyright notice. category: Database,Language
-- copyright:
category: Database
build-type: Simple build-type: Simple
extra-source-files: README,LICENSE
-- Extra files to be distributed with the package, such as examples or a
-- README.
-- extra-source-files:
-- Constraint on the version of Cabal needed to build this package.
cabal-version: >=1.10 cabal-version: >=1.10
bug-reports: https://github.com/JakeWheat/simple_sql_parser/issues
source-repository head
type: git
location: https://github.com/JakeWheat/simple_sql_parser.git
library library
-- Modules exported by the library.
exposed-modules: Pretty, Parser, Syntax exposed-modules: Pretty, Parser, Syntax
-- Modules included in this library but not exported.
-- other-modules: -- other-modules:
-- LANGUAGE extensions used by modules in this package.
-- other-extensions: -- other-extensions:
build-depends: base >=4.6 && <4.7,
-- Other library packages from which modules are imported. groom >=0.1 && <0.2,
build-depends: base >=4.6 && <4.7, groom >=0.1 && <0.2, parsec >=3.1 && <3.2, mtl >=2.1 && <2.2, haskell-src-exts >=1.14 && <1.15 parsec >=3.1 && <3.2,
mtl >=2.1 && <2.2,
-- Directories containing source files. haskell-src-exts >=1.14 && <1.15,
pretty >= 1.1 && < 1.2
-- hs-source-dirs: -- hs-source-dirs:
-- Base language which the package is written in.
default-language: Haskell2010 default-language: Haskell2010
ghc-options: -Wall