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 +25/−23
- CHANGELOG.md +13/−4
- Makefile +11/−2
- README.md +15/−2
- main/Main.hs +2/−0
- src/BNFC/Backend/Agda.hs +1/−3
- src/BNFC/Backend/C/CFtoCAbs.hs +12/−18
- src/BNFC/Backend/C/CFtoCPrinter.hs +5/−4
- src/BNFC/Backend/C/CFtoCSkel.hs +7/−7
- src/BNFC/Backend/C/Common.hs +8/−1
- src/BNFC/Backend/Haskell/CFtoAbstract.hs +5/−6
- src/BNFC/Backend/Haskell/CFtoAlex3.hs +3/−3
- src/BNFC/Backend/Haskell/CFtoHappy.hs +1/−1
- src/BNFC/Backend/Haskell/CFtoLayout.hs +1/−1
- src/BNFC/Backend/Haskell/CFtoPrinter.hs +1/−5
- src/BNFC/Backend/Haskell/MkErrM.hs +0/−47
- src/BNFC/Backend/Haskell/Utils.hs +1/−4
- src/BNFC/Backend/HaskellGADT/CFtoAbstractGADT.hs +5/−5
- src/BNFC/Backend/OCaml/CFtoOCamlLex.hs +3/−3
- src/BNFC/Backend/TreeSitter.hs +32/−0
- src/BNFC/Backend/TreeSitter/CFtoTreeSitter.hs +244/−0
- src/BNFC/Backend/TreeSitter/RegToJSReg.hs +94/−0
- src/BNFC/Backend/XML.hs +1/−1
- src/BNFC/CF.hs +3/−0
- src/BNFC/GetCF.hs +30/−21
- src/BNFC/Options.hs +9/−4
- src/BNFC/Print.hs +2/−5
- src/BNFC/Utils.hs +0/−14
- src/Makefile +4/−0
- stack-8.2.yaml +0/−1
- stack-9.10.yaml +1/−1
- stack-9.12.yaml +1/−1
- stack-9.8.yaml +1/−1
- test/BNFC/Backend/TreeSitterSpec.hs +25/−0
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"