packages feed

BNFC 2.9.5.1 → 2.9.6

raw patch · 34 files changed

+566/−188 lines, 34 filesdep −semigroupsdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: semigroups

Dependency ranges changed: base

API changes (from Hackage documentation)

- BNFC.GetCF: instance Control.Monad.Reader.Class.MonadReader BNFC.Options.SharedOptions BNFC.GetCF.Trans
+ BNFC.Backend.C.Common: memName :: String -> String
+ BNFC.Backend.TreeSitter: comment :: String -> String
+ BNFC.Backend.TreeSitter: makeTreeSitter :: SharedOptions -> CF -> Backend
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: appendComma :: Doc -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: cfToTreeSitter :: String -> CF -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: charRule :: Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: commaJoin :: Bool -> [Doc] -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: defineSymbol :: String -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: doubleRule :: Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: formatCatName :: Bool -> Cat -> String
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: formatRhs :: SentForm -> [Doc]
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: hasInternal :: [Rule] -> Bool
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: identRule :: Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: indent :: Doc -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: integerRule :: Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: prBuiltinTokenRules :: CF -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: prExtras :: CF -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: prOneCat :: [Rule] -> NonTerminal -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: prOneToken :: (TokenCat, Reg) -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: prOtherRules :: Cat -> CF -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: prRules :: CF -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: prUsrTokenRules :: CF -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: prWord :: CF -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: quoted :: String -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: refName :: String -> String
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: stringRule :: Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: wrapChoice :: [Doc] -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: wrapFun :: String -> Bool -> Doc -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: wrapOptListFun :: String -> Bool -> [Doc] -> Doc
+ BNFC.Backend.TreeSitter.CFtoTreeSitter: wrapSeq :: [Doc] -> Doc
+ BNFC.Backend.TreeSitter.RegToJSReg: instance BNFC.Backend.TreeSitter.RegToJSReg.Print BNFC.Abs.Identifier
+ BNFC.Backend.TreeSitter.RegToJSReg: instance BNFC.Backend.TreeSitter.RegToJSReg.Print BNFC.Abs.Reg
+ BNFC.Backend.TreeSitter.RegToJSReg: printRegJSReg :: Reg -> String
+ BNFC.CF: hasEntryPoint :: CFG f -> Bool
+ BNFC.GetCF: instance Control.Monad.Reader.Class.MonadReader GHC.IO.FilePath BNFC.GetCF.Trans
+ BNFC.GetCF: parseRawCF :: FilePath -> String -> Err CF
+ BNFC.Options: TargetTreeSitter :: Target

Files

BNFC.cabal view
@@ -1,5 +1,5 @@ Name: BNFC-Version: 2.9.5.1+Version: 2.9.6 cabal-version: 2.0   -- >=2.0  for build-tool-depends: hspec-discover   -- Andreas, 2022-12-16, issue #429:@@ -30,9 +30,10 @@   an XML representation,   a LaTeX file containing a readable specification of the language. +-- Support range when build with cabal tested-with:   GHC == 9.12.2-  GHC == 9.10.3+  GHC == 9.10.2   GHC == 9.8.4   GHC == 9.6.7   GHC == 9.4.8@@ -44,7 +45,6 @@   GHC == 8.4.4   GHC == 8.2.2   GHC == 8.0.2-  -- GHC == 7.10.3  extra-doc-files:   README.md@@ -67,7 +67,6 @@   stack-8.8.yaml   stack-8.6.yaml   stack-8.4.yaml-  stack-8.2.yaml  source-repository head   type:     git@@ -85,6 +84,7 @@     -- Generated by cabal     Paths_BNFC   autogen-modules:+    -- Generated by cabal     Paths_BNFC   default-extensions:     -- Keep in alphabetical order.@@ -100,7 +100,7 @@   default-language:     Haskell2010   build-depends:-      base        >= 4.8   && < 5+      base        >= 4.9   && < 5     , array     , containers     , deepseq@@ -113,9 +113,6 @@     , time     , transformers         -- for Control.Monad.IO.Class, which is in base >= 4.9 but not below-  if impl(ghc < 8)-    build-depends:-      semigroups   build-tool-depends:     alex:alex,     happy:happy@@ -123,13 +120,11 @@     src   ghc-options:     -Wall-    -fno-warn-dodgy-imports-    -fno-warn-name-shadowing+    -Wcompat+    -Wno-dodgy-imports+    -Wno-name-shadowing     -- for cabal repl -w doctest :-    -- -fno-warn-type-defaults-  if impl(ghc >= 8.0)-    ghc-options:-      -Wcompat+    -- -Wno-type-defaults   if impl(ghc >= 9.2)     ghc-options:       -Wno-incomplete-uni-patterns@@ -159,10 +154,16 @@   --   BNFC.Lex   --   -- Generated by happy   --   BNFC.Par-  other-modules:+  -- 2023-11-03 We cannot add BNFC.{Lex,Par} as then the Lex.x and Par.y files+  -- are not bundled by cabal dist.+  -- Just make sure that there is no src/BNFC/{Lex,Par}.hs before running cabal sdist,+  -- otherwise we will end up with both Lex.hs and Lex.x (resp. Par.{hs,y})+  -- which will cause alex/happy to not be run, leading to build failures.+  autogen-modules:     -- Generated by cabal     Paths_BNFC-  autogen-modules:+  other-modules:+    -- Generated by cabal     Paths_BNFC   exposed-modules:     -- Generated from LICENSE@@ -271,6 +272,11 @@     -- Agda backend     BNFC.Backend.Agda +    -- Tree-sitter backend+    BNFC.Backend.TreeSitter+    BNFC.Backend.TreeSitter.CFtoTreeSitter+    BNFC.Backend.TreeSitter.RegToJSReg+ ----- Testing --------------------------------------------------------------  test-suite unit-tests@@ -296,9 +302,6 @@     deepseq,     string-qq,     time-  if impl(ghc < 8)-    build-depends:-      semigroups   build-tool-depends:     alex:alex,     happy:happy,@@ -309,11 +312,9 @@     test   ghc-options:     -W+    -Wcompat     -- TODO: -Wall-    -fno-warn-name-shadowing-  if impl(ghc >= 8.0)-    ghc-options:-      -Wcompat+    -Wno-name-shadowing   default-extensions:     -- Keep in alphabetical order.     LambdaCase@@ -335,6 +336,7 @@     BNFC.Backend.JavaSpec     BNFC.Backend.LatexSpec     BNFC.Backend.OCamlSpec+    BNFC.Backend.TreeSitterSpec     -- Generated by cabal     Paths_BNFC   autogen-modules:
CHANGELOG.md view
@@ -1,9 +1,18 @@-# 2.9.5.1+# 2.9.6 -Andreas Abel <andreas.abel@gu.se>  Jan 2026+Andreas Abel <andreas.abel@gu.se>,  August 2025 -* Cabal 3.12 compatibility: remove generated `Lex.hs` and `Par.hs` from source tarball-* Build tested with GHC 8.0 - 9.12.2+* C: preserve case in constructors (union): e.g. label `EInt` now is union member `eInt_` rather than `eint_`+  [[#479](https://github.com/BNFC/bnfc/issues/479)]+* Haskell: lex ASCII 222 as upper rather than lower case letter+  [[#497](https://github.com/BNFC/bnfc/issues/497)]+* Haskell: no longer derive `Typeable` (obsolete since GHC 7.10)+  [[#503](https://github.com/BNFC/bnfc/issues/503)]+* Haskell: drop support for GHC 7, generated code needs at least GHC 8.0++Builds with GHC versions:+* with `cabal`, GHC 8.0 - 9.12+* with `stack`, GHC 8.4 - 9.12  # 2.9.5 
Makefile view
@@ -8,7 +8,7 @@ CABAL_BUILD_OPTS     = --enable-tests # --builddir=dist-ghc-$(GHC_VERSION)$(CABAL_BUILDDIR_SUFFIX) CABAL_CONFIGURE_OPTS = --enable-tests-CABAL_INSTALL_OPTS   = $(CABAL_CONFIGURE_OPTS) $(CABAL_BUILD_OPTS) --overwrite-policy=always+CABAL_INSTALL_OPTS   = --overwrite-policy=always CABAL_TEST_OPTS      = $(CABAL_BUILD_OPTS)  CABAL                = cabal $(CABAL_OPTS)@@ -38,7 +38,7 @@ doctest: build doctest-install doctest-quick  doctest-install:-	cabal install doctest --program-suffix=-${GHC_VERSION}+	cabal install doctest --ignore-project --program-suffix=-${GHC_VERSION}  doctest-quick: 	cabal repl -w doctest-${GHC_VERSION} --repl-options=-Wno-type-defaults@@ -62,6 +62,15 @@ # Binary package (tgz, for linux) bdist: dist/${BDIST_TAG}.tar.gz +# Source package+# Andreas, 2023-11-03, PR #466: need to remove BNFC/{Lex,Par}.hs,+# otherwise they will be shipped in the sdist package+# and cause compilation to fail.+sdist:+	make -C src clean+	cabal sdist++# OLD goal dist/%.tar.gz: 	cabal v1-clean 	cabal v1-install ${CABAL_OPTS} --only-dependencies
README.md view
@@ -43,6 +43,19 @@   bnfc --help ``` +BNFC versions in major Stackage LTS snapshots:++|  GHC   |  LTS  |  BNFC   |+|--------|-------|---------|+| 8.8.4  | 16.31 | 2.8.4   |+| 8.10.7 | 18.28 | 2.9.4   |+| 9.0.2  | 19.33 | 2.9.4   |+| 9.2.8  | 20.26 | 2.9.4.1 |+| 9.4.8  | 21.25 | 2.9.5   |+| 9.6.7  | 22.44 | 2.9.5   |+| 9.8.4  | 23.27 | 2.9.5   |+| 9.10.2 | 24.3  | 2.9.5   |+ ### Installation via cabal  You need a running installation of a recent version of@@ -71,9 +84,9 @@ ``` or ```-  stack install --stack-yaml stack-8.10.7.yaml+  stack install --stack-yaml stack-9.12.yaml ```-(replace `8.10.7` with your GHC version, and if you want to build with+(replace `9.12` with your GHC major version, and if you want to build with your installed GHC then add flag `--system-ghc`).  Mini tutorial
main/Main.hs view
@@ -25,6 +25,7 @@ import BNFC.Backend.Latex import BNFC.Backend.OCaml import BNFC.Backend.Pygments+import BNFC.Backend.TreeSitter import BNFC.CF (CF) import BNFC.GetCF import BNFC.Options hiding (make, Backend)@@ -81,3 +82,4 @@     TargetOCaml        -> makeOCaml     TargetPygments     -> makePygments     TargetCheck        -> error "impossible"+    TargetTreeSitter   -> makeTreeSitter
src/BNFC/Backend/Agda.hs view
@@ -5,9 +5,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} --- #if __GLASGOW_HASKELL__ >= 800--- {-# OPTIONS_GHC -fno-warn-unused-top-binds #-}--- #endif+-- {-# OPTIONS_GHC -Wno-unused-top-binds #-}  -- | Agda backend. --
src/BNFC/Backend/C/CFtoCAbs.hs view
@@ -35,7 +35,7 @@ import BNFC.Options  ( RecordPositions(..) ) import BNFC.Utils    ( (+++), unless ) import BNFC.Backend.Common.NamedVariables-import BNFC.Backend.C.Common ( posixC )+import BNFC.Backend.C.Common ( posixC, memName )   -- | The result is two files (.H file, .C file)@@ -304,12 +304,12 @@ --   switch(p->kind) --   { --   case is_EInt:---     return make_EInt (p->u.eint_.integer_);+--     return make_EInt (p->u.eInt_.integer_); -- <BLANKLINE> --   case is_EAdd: --     return make_EAdd---       ( clone_Exp(p->u.eadd_.exp_1)---       , clone_Exp(p->u.eadd_.exp_2)+--       ( clone_Exp(p->u.eAdd_.exp_1)+--       , clone_Exp(p->u.eAdd_.exp_2) --       ); -- <BLANKLINE> --   default:@@ -375,7 +375,7 @@   prCloneCat :: String -> (Cat, Doc) -> String   prCloneCat fnm (cat, nt) = cloner cat member     where-    member = concat [ "p->u.", map toLower fnm, "_.", render nt ]+    member = concat [ "p->u.", memName fnm, ".", render nt ]  -- | Clone or not depending on the category. --   Only pointers need to be cloned.@@ -401,8 +401,8 @@ --     break; -- <BLANKLINE> --   case is_EAdd:---     free_Exp(p->u.eadd_.exp_1);---     free_Exp(p->u.eadd_.exp_2);+--     free_Exp(p->u.eAdd_.exp_1);+--     free_Exp(p->u.eAdd_.exp_2); --     break; -- <BLANKLINE> --   default:@@ -482,8 +482,8 @@   prFreeCat fnm (cat, nt) = Just $ concat       [ maybe ("free_" ++ identCat (normCat cat)) (const "free") $ maybeTokenCat cat       , "(p->u."-      , map toLower fnm-      , "_.", render nt, ");"+      , memName fnm+      , ".", render nt, ");"       ]  @@ -614,21 +614,15 @@     prParam n c = (text (identCat c), text ("p" ++ show n))  -- | Prints the assignments of parameters to instance variables.--- >>> prAssigns "A" [("A",1),("B",2)] [text "abc", text "def"]+-- >>> prAssigns "A" [("A",1),("BA",2)] [text "abc", text "def"] -- tmp->u.a_.a_ = abc;--- tmp->u.a_.b_2 = def;+-- tmp->u.a_.ba_2 = def; prAssigns :: String -> [IVar] -> [Doc] -> Doc prAssigns c vars params = vcat $ zipWith prAssign vars params   where     prAssign (t,n) p =-        text ("tmp->u." ++ c' ++ "_." ++ vname t n) <+> char '=' <+> p <> semi+        text ("tmp->u." ++ memName c ++ "." ++ vname t n) <+> char '=' <+> p <> semi     vname t n       | n == 1, [_] <- filter ((t ==) . fst) vars                   = varName t       | otherwise = varName t ++ showNum n-    c' = map toLower c--{- **** Helper Functions **** -}--memName :: String -> String-memName s = map toLower s ++ "_"
src/BNFC/Backend/C/CFtoCPrinter.hs view
@@ -33,7 +33,8 @@  import BNFC.Backend.Common import BNFC.Backend.Common.NamedVariables-import BNFC.Backend.Common.StrUtils (renderCharOrString)+import BNFC.Backend.Common.StrUtils       ( renderCharOrString )+import BNFC.Backend.C.Common              ( memName )  -- | Produces (.h file, .c file). @@ -446,7 +447,7 @@   where     p   = precRule r     fnm = funName fun-    pre = concat [ "p->u.", map toLower fnm, "_." ]+    pre = concat [ "p->u.", memName fnm, "." ]  -- | Only render the rhs (items) of a rule. @@ -567,8 +568,8 @@   [ "    sh"   , maybe (identCat $ normCat cat) basicFunName $ maybeTokenCat cat   , "(p->u."-  , map toLower fnm-  , "_."+  , memName fnm+  , "."   , render nt   , ");\n"   ]
src/BNFC/Backend/C/CFtoCSkel.hs view
@@ -19,6 +19,7 @@ import BNFC.CF import BNFC.Utils                         ( (+++), capitalize ) import BNFC.Backend.Common.NamedVariables+import BNFC.Backend.C.Common              ( memName ) import Data.Char                          ( toLower ) import Data.Either                        ( lefts ) @@ -166,11 +167,11 @@  -- | Visits all the instance variables of a category. -- >>> let ab = Cat "Ab"--- >>> prPrintRule (Rule "Abc" undefined [Left ab, Left ab] Parsable)---   case is_Abc:---     /* Code for Abc Goes Here */---     visitAb(p->u.abc_.ab_1);---     visitAb(p->u.abc_.ab_2);+-- >>> prPrintRule (Rule "ABC" undefined [Left ab, Left ab] Parsable)+--   case is_ABC:+--     /* Code for ABC Goes Here */+--     visitAb(p->u.aBC_.ab_1);+--     visitAb(p->u.aBC_.ab_2); --     break; -- <BLANKLINE> -- >>> let ab = TokenCat "Ab"@@ -209,8 +210,7 @@       let visitf = "visit" <> if isTokenCat cat                        then basicFunName cat                        else text (identCat (normCat cat))-      in visitf <> parens ("p->u." <> text v <> "_." <> vname ) <> ";"-    where v = map toLower fnm+      in visitf <> parens ("p->u." <> text (memName fnm) <> "." <> vname ) <> ";"  -- | The visit-function name of a basic type 
src/BNFC/Backend/C/Common.hs view
@@ -1,10 +1,12 @@ -- | Common definitions for the modules of the C backend.  module BNFC.Backend.C.Common-  ( posixC+  ( memName+  , posixC   ) where  import Prelude+import BNFC.Backend.Common.NamedVariables  -- | Switch C to language variant that has @strdup@. @@ -16,3 +18,8 @@   , " */"   , "#define _POSIX_C_SOURCE 200809L"   ]++-- | Variant names in unions.++memName :: String -> String+memName s = firstLowerCase s ++ "_"
src/BNFC/Backend/Haskell/CFtoAbstract.hs view
@@ -39,15 +39,14 @@   -> CF        -- ^ Grammar.   -> Doc -- tokenText :: TokenText -- ^ Use @ByteString@ or @Text@ instead of @String@?--- generic   :: Bool      -- ^ Derive @Data@, Generic@, @Typeable@?+-- generic   :: Bool      -- ^ Derive @Data@ and Generic@? -- functor   :: Bool      -- ^ Make the tree a functor? cf2Abstract Options{ lang, tokenText, generic, functor } name cf = vsep . concat $     [ []      -- Modules header     , [ vcat . concat $-        [ [ "{-# LANGUAGE DeriveDataTypeable #-}"         | gen ]-        , [ "{-# LANGUAGE DeriveGeneric #-}"              | gen ]+        [ [ "{-# LANGUAGE DeriveGeneric #-}"              | gen ]         , [ "{-# LANGUAGE DeriveTraversable #-}"          | fun ]         , [ "{-# LANGUAGE FlexibleInstances #-}"          | fun ]         , [ "{-# LANGUAGE GeneralizedNewtypeDeriving #-}" | hasIdentLikeNoPos ] -- for IsString@@ -71,8 +70,8 @@       ]     , [ vcat . concat $         [ when hasTextualToks $ map text $ tokenTextImport tokenText-        , [ "import qualified Data.Data    as C (Data, Typeable)" | gen ]-        , [ "import qualified GHC.Generics as C (Generic)"        | gen ]+        , [ "import qualified Data.Data    as C (Data)"    | gen ]+        , [ "import qualified GHC.Generics as C (Generic)" | gen ]         ]       ] @@ -140,7 +139,7 @@      stdClasses = [ "Eq", "Ord", "Show", "Read" ]     funClasses = [ "Functor", "Foldable", "Traversable" ]-    genClasses = [ "Data", "Typeable", "Generic" ]+    genClasses = [ "Data", "Generic" ]     derivingClasses functor = map ("C." ++) $ concat       [ stdClasses       , when functor funClasses
src/BNFC/Backend/Haskell/CFtoAlex3.hs view
@@ -37,7 +37,7 @@ prelude name tokenText = concat   [ [ "-- Lexer definition for use with Alex 3"     , "{"-    , "{-# OPTIONS -fno-warn-incomplete-patterns #-}"+    , "{-# OPTIONS -Wno-incomplete-patterns #-}"     , "{-# OPTIONS_GHC -w #-}"     , ""     , "{-# LANGUAGE PatternSynonyms #-}"@@ -62,8 +62,8 @@ cMacros =   [ "-- Predefined character classes"   , ""-  , "$c = [A-Z\\192-\\221] # [\\215]  -- capital isolatin1 letter (215 = \\times) FIXME"-  , "$s = [a-z\\222-\\255] # [\\247]  -- small   isolatin1 letter (247 = \\div  ) FIXME"+  , "$c = [A-Z\\192-\\222] # [\\215]  -- capital isolatin1 letter (215 = \\times)"+  , "$s = [a-z\\223-\\255] # [\\247]  -- small   isolatin1 letter (247 = \\div  )"   , "$l = [$c $s]         -- letter"   , "$d = [0-9]           -- digit"   , "$i = [$l $d _ ']     -- identifier character"
src/BNFC/Backend/Haskell/CFtoHappy.hs view
@@ -62,7 +62,7 @@ header modName absName lexName tokenText eps = unlines $ concat   [ [ "-- Parser definition for use with Happy"     , "{"-    , "{-# OPTIONS_GHC -fno-warn-incomplete-patterns -fno-warn-overlapping-patterns #-}"+    , "{-# OPTIONS_GHC -Wno-incomplete-patterns -Wno-overlapping-patterns #-}"     , "{-# LANGUAGE PatternSynonyms #-}"     , ""     , "module " ++ modName
src/BNFC/Backend/Haskell/CFtoLayout.hs view
@@ -23,7 +23,7 @@  cf2Layout :: String -> String -> CF -> String cf2Layout layName lexName cf = unlines $ concat-  [ [ "{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}"+  [ [ "{-# OPTIONS_GHC -Wno-incomplete-patterns #-}"     , ""     , "{-# LANGUAGE LambdaCase #-}"     , "{-# LANGUAGE PatternGuards #-}"
src/BNFC/Backend/Haskell/CFtoPrinter.hs view
@@ -63,13 +63,9 @@     , "{-# LANGUAGE LambdaCase #-}"     ]   , [ "{-# LANGUAGE GADTs #-}"                | useGadt ]-  , [ "#if __GLASGOW_HASKELL__ <= 708"-    , "{-# LANGUAGE OverlappingInstances #-}"-    , "#endif"-    ]   , [ ""     -- -- WAS: Needed for precedence category lists, e.g. @[Exp2]@:-    -- , "{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}"+    -- , "{-# OPTIONS_GHC -Wno-incomplete-patterns #-}"     -- , ""     , "-- | Pretty-printer for " ++ takeWhile ('.' /=) name ++ "."     , ""
src/BNFC/Backend/Haskell/MkErrM.hs view
@@ -16,10 +16,6 @@ mkErrM errMod = vcat     [ "{-# LANGUAGE CPP #-}"     , ""-    , "#if __GLASGOW_HASKELL__ >= 708"-    , "---------------------------------------------------------------------------"-    , "-- Pattern synonyms exist since ghc 7.8."-    , ""     , "-- | BNF Converter: Error Monad."     , "--"     , "-- Module for backwards compatibility."@@ -60,47 +56,4 @@     , "instance MonadPlus Err where"     , "  mzero = empty"     , "  mplus = (<|>)"-    , ""-    , "#else"-    , "---------------------------------------------------------------------------"-    , "-- ghc 7.6 and before: use old definition as data type."-    , ""-    , "-- | BNF Converter: Error Monad"-    , ""-    , "-- Copyright (C) 2004  Author:  Aarne Ranta"-    , "-- This file comes with NO WARRANTY and may be used FOR ANY PURPOSE."-    , ""-    , "module" <+> text errMod <+> "where"-    , ""-    , "-- the Error monad: like Maybe type with error msgs"-    , ""-    , "import Control.Applicative (Applicative(..), Alternative(..))"-    , "import Control.Monad       (MonadPlus(..), liftM)"-    , ""-    , "data Err a = Ok a | Bad String"-    , "  deriving (Read, Show, Eq, Ord)"-    , ""-    , "instance Monad Err where"-    , "  return      = Ok"-    , "  Ok a  >>= f = f a"-    , "  Bad s >>= _ = Bad s"-    , ""-    , "instance Applicative Err where"-    , "  pure = Ok"-    , "  (Bad s) <*> _ = Bad s"-    , "  (Ok f) <*> o  = liftM f o"-    , ""-    , "instance Functor Err where"-    , "  fmap = liftM"-    , ""-    , "instance MonadPlus Err where"-    , "  mzero = Bad \"Err.mzero\""-    , "  mplus (Bad _) y = y"-    , "  mplus x       _ = x"-    , ""-    , "instance Alternative Err where"-    , "  empty = mzero"-    , "  (<|>) = mplus"-    , ""-    , "#endif"     ]
src/BNFC/Backend/Haskell/Utils.hs view
@@ -38,10 +38,7 @@ -- * GHC pragmas  noWarnUnusedMatches :: IsString a => a-noWarnUnusedMatches =-  "{-# OPTIONS_GHC -fno-warn-unused-matches #-}"-  -- ALT: only from GHC 8-  -- "{-# OPTIONS_GHC -Wno-unused-matches #-}"+noWarnUnusedMatches = "{-# OPTIONS_GHC -Wno-unused-matches #-}"  -- * Names for position data type. 
src/BNFC/Backend/HaskellGADT/CFtoAbstractGADT.hs view
@@ -27,14 +27,14 @@   , [ "{-# LANGUAGE EmptyCase #-}" | emptyTree ]   , [ "{-# LANGUAGE LambdaCase #-}"     , ""-    , "{-# OPTIONS_GHC -fno-warn-unused-binds #-}"+    , "{-# OPTIONS_GHC -Wno-unused-binds #-}"       -- unused-local-binds would be sufficient, but parses only from GHC 8.0-    , "{-# OPTIONS_GHC -fno-warn-unused-imports #-}"-    , "{-# OPTIONS_GHC -fno-warn-unused-matches #-}"-    , "{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}"+    , "{-# OPTIONS_GHC -Wno-unused-imports #-}"+    , "{-# OPTIONS_GHC -Wno-unused-matches #-}"+    , "{-# OPTIONS_GHC -Wno-incomplete-patterns #-}"       -- defects of coverage checker, e.g. in 8.2.2, may lead to warning       -- about exceeded iterations for pattern match checker-    , "{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}"+    , "{-# OPTIONS_GHC -Wno-overlapping-patterns #-}"     , ""     , "module" +++ name +++ "(" ++ List.intercalate ", " exports ++ ")" +++ "where"     , ""
src/BNFC/Backend/OCaml/CFtoOCamlLex.hs view
@@ -98,9 +98,9 @@ cMacros :: [String] cMacros =   [ "(* BNFC character classes *)"-  , "let _letter = ['a'-'z' 'A'-'Z' '\\192' - '\\255'] # ['\\215' '\\247']    (*  isolatin1 letter FIXME *)"-  , "let _upper  = ['A'-'Z' '\\192'-'\\221'] # '\\215'      (*  capital isolatin1 letter FIXME *)"-  , "let _lower  = ['a'-'z' '\\222'-'\\255'] # '\\247'      (*  small isolatin1 letter FIXME *)"+  , "let _letter = ['A'-'Z' 'a'-'z' '\\181' '\\192' - '\\255'] # ['\\215' '\\247']    (*  isolatin1 letter *)"+  , "let _upper  = ['A'-'Z' '\\192'-'\\222'] # '\\215'      (*  capital isolatin1 letter *)"+  , "let _lower  = ['a'-'z' '\\181' '\\223'-'\\255'] # '\\247'      (*  small isolatin1 letter *)"   , "let _digit  = ['0'-'9']                             (*  _digit *)"   , "let _idchar = _letter | _digit | ['_' '\\'']         (*  identifier character *)"   , "let _universal = _                                  (* universal: any character *)"
+ src/BNFC/Backend/TreeSitter.hs view
@@ -0,0 +1,32 @@+{-+    BNF Converter: TreeSitter Grammar Generator+    Copyright (C) 2004  Author:  Markus Forsberg, Michael Pellauer,+                                 Bjorn Bringert++    Description   : This module generates the grammar.js input file for+                    tree-sitter.++    Author        : Kangjing Huang (huangkangjing@gmail.com)+    Created       : 23 Nov, 2023++-}++module BNFC.Backend.TreeSitter where++import BNFC.Backend.Base+import BNFC.Backend.TreeSitter.CFtoTreeSitter (cfToTreeSitter)+import BNFC.CF+import BNFC.Options hiding (Backend)+import BNFC.PrettyPrint++-- | Entry point: create grammar.js file+makeTreeSitter :: SharedOptions -> CF -> Backend+makeTreeSitter opts cf = do+  mkfile "grammar.js" comment (render $ cfToTreeSitter name cf)+  where+    name = lang opts++comment :: String -> String+comment = ("// " ++)++-- | TODO: Add Makefile generation for tree-sitter
+ src/BNFC/Backend/TreeSitter/CFtoTreeSitter.hs view
@@ -0,0 +1,244 @@+{-+    BNF Converter: TreeSitter Grammar Generator+    Copyright (C) 2004  Author:  Markus Forsberg, Michael Pellauer,+                                 Bjorn Bringert++    Description   : This module converts BNFC grammar to the contents of a+                    tree-sitter grammar.js file++    Author        : Kangjing Huang (huangkangjing@gmail.com)+    Created       : 08 Nov, 2023++-}++module BNFC.Backend.TreeSitter.CFtoTreeSitter where++import BNFC.Abs (Reg (RSeq, RSeqs, RStar, RAny))+import BNFC.Backend.TreeSitter.RegToJSReg+import BNFC.CF+import BNFC.Lexing (mkRegMultilineComment)+import BNFC.PrettyPrint+import Prelude hiding ((<>))++-- | Indent one level of 2 spaces+indent :: Doc -> Doc+indent = nest 2++-- | Create content of grammar.js file+cfToTreeSitter :: String -> CF -> Doc+cfToTreeSitter name cf =+  -- Overall structure of grammar.js+  text "module.exports = grammar({"+    $+$ indent+      ( text "name: '" <> text name <> text "',"+          $+$ extrasSection+          $+$ wordSection+          $+$ rulesSection+      )+    $+$ text "});"+  where+    extrasSection = prExtras cf+    wordSection = prWord cf+    rulesSection =+      text "rules: {"+        $+$ indent+          ( prRules cf+              $+$ prUsrTokenRules cf+              $+$ prBuiltinTokenRules cf+          )+        $+$ text "},"++-- | Print rules for comments+prExtras :: CF -> Doc+prExtras cf =+  if extraNeeded+    then+      defineSymbol "extras" <> "["+        $+$ indent+          ( -- default rule for white spaces+            text "/\\s/,"+              $+$ mRules+              $+$ sRules+          )+        $+$ text "],"+    else empty+  where+    extraNeeded = length commentMRules + length commentSRules > 0+    (commentMRules, commentSRules) = comments cf+    mRules = vcat' $ map mkOneMRule commentMRules+    sRules = vcat' $ map mkOneSRule commentSRules+    mkOneSRule s = text (printRegJSReg $ RSeq (RSeqs s) (RStar RAny)) <> text ","+    mkOneMRule (s, e) = text (printRegJSReg $ mkRegMultilineComment s e) <> text ","++-- | Print word section, this section is needed for tree-sitter+--   to do keyword extraction before any parsing/lexing, see+--   https://tree-sitter.github.io/tree-sitter/creating-parsers#keyword-extraction+--   TODO: currently, we just add every user defined token as well+--   as the predefined Ident token to this list to be safe. Ideally,+--   we should enumerate all defined tokens against all occurrences of+--   keywords. Any tokens patterns that could accept a keyword will go+--   into this list. This will require integration of a regex engine.+prWord :: CF -> Doc+prWord cf =+  if wordNeeded+    then+      defineSymbol "word"+        $+$ indent+          ( wrapChoice+              ( usrTokensFormatted+                  ++ [text "$.token_Ident" | identUsed]+              )+          )+          <> ","+    else empty+  where+    wordNeeded = identUsed || usrTokens /= []+    identUsed = isUsedCat cf (TokenCat catIdent)+    usrTokens = tokenPragmas cf+    usrTokensFormatted =+      map (text . refName . formatCatName False . TokenCat . fst) $ usrTokens++-- | Print builtin token rules according to their usage+prBuiltinTokenRules :: CF -> Doc+prBuiltinTokenRules cf =+  ifC catInteger integerRule+    $+$ ifC catDouble doubleRule+    $+$ ifC catChar charRule+    $+$ ifC catString stringRule+    $+$ ifC catIdent identRule+  where+    ifC cat d = if isUsedCat cf (TokenCat cat) then d else empty++-- | Predefined builtin token rules+integerRule, doubleRule, charRule, stringRule, identRule :: Doc+integerRule = defineSymbol "token_Integer" <+> text "/\\d+/" <> ","+doubleRule = defineSymbol "token_Double" <+> text "/\\d+\\.\\d+(e-?\\d+)?/" <> ","+charRule =+  defineSymbol "token_Char" <+> text "/'([^'\\\\]|(\\\\[\"'\\\\tnrf]))'/" <> ","+stringRule =+  defineSymbol "token_String" <+> text "/\"([^'\\\\]|(\\\\[\"'\\\\tnrf]))*\"/" <> ","+identRule =+  defineSymbol "token_Ident" <+> text "/[a-zA-Z][a-zA-Z\\d_']*/" <> ","++-- | First print the entrypoint rule, tree-sitter always use the+--   first rule as entrypoint and does not support multi-entrypoint.+--   Then print rest of the rules+prRules :: CF -> Doc+prRules cf =+  if onlyOneEntry+    then+      prOneCat entryRules entryCat+        $+$ prOtherRules entryCat cf+    else error "Tree-sitter only supports one entrypoint"+  where+    --If entrypoint is defined, there must be only one entrypoint+    --If it is not defined, defaults to use the first rule as entrypoint+    onlyOneEntry = not (hasEntryPoint cf) || onlyOneEntryDefined+    onlyOneEntryDefined = length (allEntryPoints cf) == 1+    entryCat = firstEntry cf+    entryRules = rulesForCat' cf entryCat++-- | Print all other rules except the entrypoint+prOtherRules :: Cat -> CF -> Doc+prOtherRules entryCat cf = vcat' $ map mkOne rules+  where+    rules = [(c, r) | (c, r) <- ruleGroupsInternals cf, c /= entryCat]+    mkOne (cat, rules) = prOneCat rules cat++prUsrTokenRules :: CF -> Doc+prUsrTokenRules cf = vcat' $ map prOneToken tokens+  where+    tokens = tokenPragmas cf++-- | Check if a set of rules contains internal rules+hasInternal :: [Rule] -> Bool+hasInternal = not . all isParsable++-- | Generates one or two tree-sitter rule(s) for one non-terminal from CF.+-- Uses choice function from tree-sitter to combine rules for the non-terminal+-- If the non-terminal has internal rules, an internal version of the non-terminal+-- will be created (prefixed with "_" in tree-sitter), and all internal rules will+-- be sectioned as such.+prOneCat :: [Rule] -> NonTerminal -> Doc+prOneCat rules nt =+  defineSymbol (formatCatName False nt)+    $+$ indent (appendComma parRhs)+    $+$ internalRules+  where+    int = hasInternal rules+    internalRules =+      if int+        then defineSymbol (formatCatName True nt) $+$ indent (appendComma intRhs)+        else empty+    parRhs = wrapChoice $ transChoice ++ genChoice (filter isParsable rules)+    transChoice = [text $ refName $ formatCatName True nt | int]+    intRhs = wrapChoice $ genChoice (filter (not . isParsable) rules)+    genChoice = map (wrapSeq . formatRhs . rhsRule)++-- | Generate one tree-sitter rule for one defined token+prOneToken :: (TokenCat, Reg) -> Doc+prOneToken (cat, exp) =+  defineSymbol (formatCatName False $ TokenCat cat)+    $+$ indent (text $ printRegJSReg exp) <> ","++-- | Start a defined symbol block in tree-sitter grammar+defineSymbol :: String -> Doc+defineSymbol name = hsep [text name <> ":", text "$", text "=>"]++appendComma :: Doc -> Doc+appendComma = (<> text ",")++commaJoin :: Bool -> [Doc] -> Doc+commaJoin newline =+  foldl comma empty+  where+    comma a b+      | isEmpty a = b+      | isEmpty b = a+      | otherwise = (if newline then ($+$) else (<>)) (a <> ",") b++wrapSeq :: [Doc] -> Doc+wrapSeq = wrapOptListFun "seq" False++wrapChoice :: [Doc] -> Doc+wrapChoice = wrapOptListFun "choice" True++-- | Wrap list using tree-sitter fun if the list contains multiple items+-- Returns the only item without wrapping otherwise+wrapOptListFun :: String -> Bool -> [Doc] -> Doc+wrapOptListFun fun newline list =+  if length list == 1+    then head list+    else wrapFun fun newline (commaJoin newline list)++wrapFun :: String -> Bool -> Doc -> Doc+wrapFun fun newline arg = joinOp [text fun <> text "(", indent arg, text ")"]+  where+    joinOp = if newline then vcat' else hcat++-- | Helper for referring to non-terminal names in tree-sitter+refName :: String -> String+refName = ("$." ++)++-- | Format right hand side into list of strings+formatRhs :: SentForm -> [Doc]+formatRhs =+  map (\case+    Left c -> text $ refName $ formatCatName False c+    Right term -> quoted term)++quoted :: String -> Doc+quoted s = text "\"" <> text s <> text "\""++-- | Format string for cat name, prefix "_" if the name is for internal rules+formatCatName :: Bool -> Cat -> String+formatCatName internal c =+  if internal+    then "_" ++ formatted+    else formatted+  where+    formatted = formatName c+    formatName (Cat name) = name+    formatName (TokenCat name) = "token_" ++ name+    formatName (ListCat c) = "list_" ++ formatName c+    formatName (CoercCat name i) = name ++ show i
+ src/BNFC/Backend/TreeSitter/RegToJSReg.hs view
@@ -0,0 +1,94 @@+{-+    BNF Converter: TreeSitter Grammar Generator+    Copyright (C) 2004  Author:  Markus Forsberg, Michael Pellauer,+                                 Bjorn Bringert++    Description   : This module converts BNFC Reg to Javascript regular+                    expressions that is used in++    Author        : Kangjing Huang (huangkangjing@gmail.com)+    Created       : 23 Nov, 2023++-}+{-# LANGUAGE LambdaCase #-}++module BNFC.Backend.TreeSitter.RegToJSReg (printRegJSReg) where++import BNFC.Abs++printRegJSReg :: Reg -> String+printRegJSReg r = "/" ++ render (prt 0 r) ++ "/"++-- There is no space-based formatting for javascript regex+-- We just concat everything together+render :: [String] -> String+render = concat++parenth :: [String] -> [String]+parenth s = ["("] ++ s ++ [")"]++-- Printer class+class Print a where+  prt :: Int -> a -> [String]++prPrec :: Int -> Int -> [String] -> [String]+prPrec i j = if i > j then parenth else id++-- | reserved characters for Javascript regex format, sourced from+--   https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#escaping+reserved :: String+reserved = ".*+?^${}()|[]\\/"++-- | reserved characters for alt expressions in Javascript regex format+reservedAlt :: String+reservedAlt = "^[]-\\/"++-- | Pattern for matching empty string in Javascript regex format+emptyPat :: String+emptyPat = " [^\\u0000-\\uFFFF]?"++-- | escape character according to Javascript regex format+escapeCharFrom :: String -> Char -> String+escapeCharFrom reservedChars x+  | x `elem` reservedChars = '\\' : [x]+  | otherwise = [x]++escapeChar :: Char -> String+escapeChar = escapeCharFrom reserved++escapeStr :: String -> String+escapeStr = concatMap escapeChar++escapeCharAlt :: Char -> String+escapeCharAlt = escapeCharFrom reservedAlt++escapeStrAlt :: String -> String+escapeStrAlt = concatMap escapeChar++instance Print Identifier where+  prt _ (Identifier (_, i)) = [i]++instance Print Reg where+  prt i = \case+    RSeq reg0 reg -> prPrec i 2 $ prt 2 reg0 ++ prt 3 reg+    RAlt reg0 reg -> prPrec i 1 $ prt 1 reg0 ++  ["|"] ++ prt 2 reg+    -- Javascript regex does not support general set difference+    RMinus reg0 REps -> prt i reg0 -- REps is identity for difference+    RMinus RAny (RChar c) -> ["[^" ++ escapeCharAlt c ++ "]"]+    RMinus RAny (RAlts s) -> ["[^" ++ escapeStrAlt s ++ "]"]+    -- TODO: It is possible to use external scanners in tree-sitter:+    -- https://tree-sitter.github.io/tree-sitter/creating-parsers#external-scanners+    -- to support general set differences in the future+    RMinus _ _ -> error "Javascript regex does not support general set differences"+    RStar reg -> prt 3 reg ++ ["*"]+    RPlus reg -> prt 3 reg ++ ["+"]+    ROpt reg -> prt 3 reg ++ ["?"]+    REps -> [emptyPat]+    RChar c -> [escapeChar c]+    RAlts str -> ["[" ++ escapeStrAlt str ++ "]"]+    RSeqs str -> [escapeStr str]+    RDigit -> ["\\d"]+    RLetter -> ["[a-zA-Z]"]+    RUpper -> ["[A-Z]"]+    RLower -> ["[a-z]"]+    RAny -> ["."]
src/BNFC/Backend/XML.hs view
@@ -7,7 +7,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} -{-# OPTIONS_GHC -fno-warn-missing-signatures #-}+{-# OPTIONS_GHC -Wno-missing-signatures #-}  module BNFC.Backend.XML ---- (cf2DTD, cf2XML)   where
src/BNFC/CF.hs view
@@ -783,6 +783,9 @@ isPositionCat :: CFG f -> TokenCat -> Bool isPositionCat cf cat = or [ b | TokenReg name b _ <- cfgPragmas cf, wpThing name == cat] +-- | Is there a explicitly defined @entrypoint@ pragma?+hasEntryPoint :: CFG f -> Bool+hasEntryPoint cf = or [ True | EntryPoints{} <- cfgPragmas cf]  -- | Categories that are entry points to the parser. --
src/BNFC/GetCF.hs view
@@ -18,12 +18,12 @@ -- | Check LBNF input file and turn it into the 'CF' internal representation.  module BNFC.GetCF-  ( parseCF+  ( parseCF, parseRawCF   , checkRule, transItem   ) where  import Control.Arrow (left)-import Control.Monad.Reader (ReaderT, runReaderT, MonadReader(..), asks)+import Control.Monad.Reader (ReaderT, runReaderT, MonadReader(..), ask) import Control.Monad.State (State, evalState, get, modify) import Control.Monad.Except (MonadError(..)) @@ -63,19 +63,24 @@ -- $setup -- >>> import BNFC.Print --- | Entrypoint.+-- | Parse raw CF from LBNF file without checking backend requirements -parseCF :: SharedOptions -> Target -> String -> IO CF-parseCF opts target content = do-  cf <- runErr $ pGrammar (myLexer content)+parseRawCF :: FilePath -> String -> Err CF+parseRawCF fileName content = pGrammar (myLexer content)                     -- <&> expandRules -- <&> from ghc 8.4                     >>= return . expandRules-                    >>= getCF opts+                    >>= getCF fileName                     >>= return . markTokenCategories+                    -- Construct the typing information in 'define' expressions.+                    >>= runTypeChecker . checkDefinitions -  -- Construct the typing information in 'define' expressions.-  cf <- either die return $ runTypeChecker $ checkDefinitions cf+-- | Entrypoint. Parses full CF from LBNF file and checks against+--   all backend requirements +parseCF :: SharedOptions -> Target -> String -> IO CF+parseCF opts target content = do+  cf <- runErr $ parseRawCF (lbnfFile opts) content+   -- Some backends do not allow the grammar name to coincide with   -- one of the category or constructor names.   let names    = allNames cf@@ -162,9 +167,13 @@             ]    -- Warn or fail if the grammar uses names not unique modulo upper/lowercase.-  when False $-   case nub $ filter (`notElem` nonUniqueNames) $ filter (not . isDefinedRule) $-       concatMap List1.toList $ duplicatesOn (map toLower . wpThing) names of+  case nub+    . filter (`notElem` nonUniqueNames)+    . concatMap List1.toList+    . duplicatesOn (map toLower . wpThing)+    . filter (not . isDefinedRule)+    $ names+    of     [] -> return ()     ns | target `elem` [ TargetJava ]        -> dieUnlessForce $ unlines $ concat@@ -259,9 +268,9 @@ -- | Translate the parsed grammar file into a context-free grammar 'CF'. --   Desugars and type-checks. -getCF :: SharedOptions -> Abs.Grammar -> Err CF-getCF opts (Abs.Grammar defs) = do-    (pragma, rules) <- partitionEithers . concat <$> mapM transDef defs `runTrans` opts+getCF :: FilePath -> Abs.Grammar -> Err CF+getCF inputFile (Abs.Grammar defs) = do+    (pragma, rules) <- partitionEithers . concat <$> mapM transDef defs `runTrans` inputFile     let reservedWords      = nub [ t | r <- rules, isParsable r, Right t <- rhsRule r, not $ all isSpace t ]           -- Issue #204: exclude keywords from internal rules           -- Issue #70: whitespace separators should be treated like "", at least in the parser@@ -345,10 +354,10 @@     }  -- | Translation monad.-newtype Trans a = Trans { unTrans :: ReaderT SharedOptions Err a }-  deriving (Functor, Applicative, Monad, MonadReader SharedOptions, MonadError String)+newtype Trans a = Trans { unTrans :: ReaderT FilePath Err a }+  deriving (Functor, Applicative, Monad, MonadReader FilePath, MonadError String) -runTrans :: Trans a -> SharedOptions -> Err a+runTrans :: Trans a -> FilePath -> Err a runTrans m opts = unTrans m `runReaderT` opts  transDef :: Abs.Def -> Trans [Either Pragma Rule]@@ -447,7 +456,7 @@  ebnfRules :: Abs.Identifier -> [Abs.RHS] -> Trans [Rule] ebnfRules (Abs.Identifier ((line, col), c)) rhss = do-  file <- asks lbnfFile+  file <- ask   let wp = WithPosition $ Position file line col   let rule x rhs = Rule (wp x) (wp $ strToCat c) rhs Parsable   return@@ -487,7 +496,7 @@ transCat = \case     Abs.ListCat cat                             -> fmap ListCat <$> transCat cat     Abs.IdCat (Abs.Identifier ((line, col), c)) -> do-      file <- asks lbnfFile+      file <- ask       return $ WithPosition (Position file line col) $ strToCat c  transLabel :: Abs.Label -> Trans RFun@@ -500,7 +509,7 @@  transIdent :: Abs.Identifier -> Trans RString transIdent (Abs.Identifier ((line, col), str)) = do-  file <- asks lbnfFile+  file <- ask   return $ WithPosition (Position file line col) str  transArg :: Abs.Arg -> (String, Base)
src/BNFC/Options.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TupleSections #-} -{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -Wno-orphans #-}  module BNFC.Options   ( Mode(..), Target(..), Backend@@ -63,6 +63,7 @@ data Target = TargetC | TargetCpp | TargetCppNoStl             | TargetHaskell | TargetHaskellGadt | TargetLatex             | TargetJava | TargetOCaml | TargetPygments+            | TargetTreeSitter             | TargetCheck   deriving (Eq, Bounded, Enum, Ord) @@ -80,6 +81,7 @@   show TargetJava         = "Java"   show TargetOCaml        = "OCaml"   show TargetPygments     = "Pygments"+  show TargetTreeSitter   = "Tree-sitter"   show TargetCheck        = "Check LBNF file"  -- | Which version of Alex is targeted?@@ -132,7 +134,7 @@   --- Haskell specific:   , inDir         :: Bool        -- ^ Option @-d@.   , functor       :: Bool        -- ^ Option @--functor@.  Make AST functorial?-  , generic       :: Bool        -- ^ Option @--generic@.  Derive Data, Generic, Typeable?+  , generic       :: Bool        -- ^ Option @--generic@.  Derive Data and Generic?   , alexMode      :: AlexVersion -- ^ Options @--alex@.   , tokenText     :: TokenText   -- ^ Options @--bytestrings@, @--string-token@, and @--text-token@.   , glr           :: HappyMode   -- ^ Happy option @--glr@.@@ -258,6 +260,7 @@   TargetJava        -> "java"   TargetOCaml       -> "ocaml"   TargetPygments    -> "pygments"+  TargetTreeSitter  -> "tree-sitter"   TargetCheck       -> "check"  printAlexOption :: AlexVersion -> String@@ -309,6 +312,8 @@     "Output OCaml code for use with ocamllex and menhir (short for --ocaml --menhir)"   , Option "" ["pygments"]      (NoArg (\o -> o {target = TargetPygments}))     "Output a Python lexer for Pygments"+  , Option "" ["tree-sitter"]   (NoArg (\o -> o {target = TargetTreeSitter}))+    "Output grammar.js file for use with tree-sitter"   , Option "" ["check"]         (NoArg (\ o -> o{target = TargetCheck }))     "No output. Just check input LBNF file"   ]@@ -373,7 +378,7 @@           "Make the AST a functor and use it to store the position of the nodes"     , haskellTargets )   , ( Option []    ["generic"] (NoArg (\o -> o {generic = True}))-          "Derive Data, Generic, and Typeable instances for AST types"+          "Derive Data and Generic instances for AST types"     , haskellTargets )   , ( Option []    ["xml"] (NoArg (\o -> o {xml = 1}))           "Also generate a DTD and an XML printer"@@ -524,6 +529,7 @@     TargetJava        -> True     TargetOCaml       -> True     TargetPygments    -> True+    TargetTreeSitter  -> True     TargetCheck       -> True  instance Maintained AlexVersion where@@ -654,5 +660,4 @@     , ("-generic"             , "--generic")     , ("--ghc"                , "--generic")     , ("--deriveGeneric"      , "--generic")-    , ("--deriveDataTypeable" , "--generic")     ]
src/BNFC/Print.hs view
@@ -1,13 +1,10 @@--- File generated by the BNF Converter (bnfc 2.9.3).+-- File generated by the BNF Converter (bnfc 2.9.6).  {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-}-#if __GLASGOW_HASKELL__ <= 708-{-# LANGUAGE OverlappingInstances #-}-#endif -{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}+{-# OPTIONS_GHC -Wno-incomplete-patterns #-}  -- | Pretty-printer for BNFC. 
src/BNFC/Utils.hs view
@@ -3,8 +3,6 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE PatternSynonyms #-} -{-# OPTIONS_GHC -fno-warn-orphans #-}  -- ghc 7.10- module BNFC.Utils     ( ModuleName     , when, unless, unlessNull, unlessNull'@@ -56,18 +54,6 @@ type ModuleName = String  -- * Control flow.---- ghc 7.10 misses the instance Monoid a => Monoid (IO a)--#if __GLASGOW_HASKELL__ <= 710-instance {-# OVERLAPPING #-} Semigroup (IO ()) where-  (<>) = (>>)--instance {-# OVERLAPPING #-} Monoid (IO ()) where-  mempty  = return ()-  mappend = (<>)-  mconcat = sequence_-#endif  -- | Generalization of 'Control.Monad.when'. when :: Monoid m => Bool -> m -> m
src/Makefile view
@@ -62,4 +62,8 @@ rm-fake-cabal : 	rm inferior-haskell-find-project-root.cabal +.PHONY: clean+clean :+	rm BNFC/Lex.hs BNFC/Par.hs BNFC/*.bak+ #EOF
− stack-8.2.yaml
@@ -1,1 +0,0 @@-resolver: lts-11.22
stack-9.10.yaml view
@@ -1,1 +1,1 @@-resolver: lts-24.15+resolver: lts-24.3
stack-9.12.yaml view
@@ -1,3 +1,3 @@-resolver: nightly-2025-10-14+resolver: nightly-2025-08-08 compiler: ghc-9.12.2 compiler-check: newer-minor
stack-9.8.yaml view
@@ -1,4 +1,4 @@-resolver: lts-23.28+resolver: lts-23.27 compiler: ghc-9.8.4 compiler-check: newer-minor 
+ test/BNFC/Backend/TreeSitterSpec.hs view
@@ -0,0 +1,25 @@+module BNFC.Backend.TreeSitterSpec where++import BNFC.Options+import BNFC.GetCF++import Test.Hspec+import BNFC.Hspec++import BNFC.Backend.TreeSitter -- SUT++calcOptions = defaultOptions { lang = "Calc" }+getCalc = parseCF  calcOptions TargetTreeSitter $+  unlines [ "EAdd. Exp ::= Exp \"+\" Exp1  ;"+          , "ESub. Exp ::= Exp \"-\" Exp1  ;"+          , "EMul. Exp1  ::= Exp1  \"*\" Exp2  ;"+          , "EDiv. Exp1  ::= Exp1  \"/\" Exp2  ;"+          , "EInt. Exp2  ::= Integer ;"+          , "coercions Exp 2 ;" ]++spec = do++  describe "Tree-Sitter backend" $ do+    it "creates the grammar.js file" $ do+      calc <- getCalc+      makeTreeSitter calcOptions calc `shouldGenerate` "grammar.js"