mirror of
https://github.com/zap-proto/haskell.git
synced 2026-10-30 15:05:00 +00:00
Library + zapc-haskell already compiled; this finishes the test suite and CI: - SchemaGeneration.hs: import Control.Monad (replicateM) — mtl 2.3 stopped re-exporting Control.Monad from Control.Monad.State.Strict. - Module/Zap/Rpc.hs (expectException): GHC 9.6's stricter ambiguity check + waitPipeline's ReprFor a ~ 'Ptr pr rewrite broke the fundep-resolved Parse constraint. Pin the parsed type to and annotate the bound result (forall + ScopedTypeVariables) so GHC discharges Parse a (Parsed a) directly. - Regression.hs: regenerate the issue-#56 abort-message wire bytes — the rebrand find-replaced capnproto->zap INSIDE the binary literal, shortening the embedded text without updating the list-pointer length -> TraversalLimitError. Rebuilt via parsedToLBS of the expected Message. - zap-tests.cabal: drop the phantom 'benchmark bench' stanza (bench/Main.hs was never in the repo) and the broken examples/ test source dirs. - cabal.project: allow-newer lifetimes:transformers (stale upstream bound; GHC 9.4+ ships transformers 0.6 and lifetimes compiles against it). - ci.yml: build+install the zap schema front-end from cpp-core (the integration tests shell out to it), mirroring the Rust install-zap step. Local: cabal build all + cabal test all => 165 examples, 0 failures (GHC 9.6.7).
194 lines
4.3 KiB
Haskell
194 lines
4.3 KiB
Haskell
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
|
|
|
module SchemaGeneration
|
|
( Schema (..),
|
|
genSchema,
|
|
)
|
|
where
|
|
|
|
import Control.Monad (replicateM)
|
|
import Control.Monad.State.Strict
|
|
import Data.List.NonEmpty (NonEmpty ((:|)))
|
|
import qualified Data.List.NonEmpty as NE
|
|
import qualified Test.QuickCheck as QC
|
|
|
|
-- Definitions
|
|
|
|
newtype FieldName
|
|
= FieldName String
|
|
|
|
instance Show FieldName where
|
|
show (FieldName fn) = fn
|
|
|
|
newtype StructName
|
|
= StructName String
|
|
|
|
instance Show StructName where
|
|
show (StructName fn) = fn
|
|
|
|
data Field
|
|
= FieldDef FieldName Int FieldType
|
|
| StructDef StructName [Field]
|
|
|
|
data BuiltIn
|
|
= Void
|
|
| Bool
|
|
| Int8
|
|
| Int16
|
|
| Int32
|
|
| Int64
|
|
| UInt8
|
|
| UInt16
|
|
| UInt32
|
|
| UInt64
|
|
| Float32
|
|
| Float64
|
|
| Text
|
|
| Data
|
|
deriving (Show, Enum)
|
|
|
|
data FieldType
|
|
= BasicType BuiltIn
|
|
| ListType FieldType
|
|
| StructType StructName
|
|
|
|
instance Show FieldType where
|
|
show (BasicType bi) = show bi
|
|
show (ListType ft) = "List(" ++ show ft ++ ")"
|
|
show (StructType sn) = show sn
|
|
|
|
instance Show Field where
|
|
show (FieldDef name order entryType) =
|
|
concat
|
|
[ show name,
|
|
" @",
|
|
show order,
|
|
" :",
|
|
show entryType,
|
|
";\n"
|
|
]
|
|
show (StructDef name content) =
|
|
concat
|
|
[ "struct ",
|
|
show name,
|
|
" {\n",
|
|
concatMap (('\t' :) . show) content,
|
|
"}\n\n"
|
|
]
|
|
|
|
data Schema = Schema
|
|
{ schemaId :: String,
|
|
schemaContent :: [Field]
|
|
}
|
|
|
|
instance Show Schema where
|
|
show s =
|
|
concat
|
|
[ "@0x",
|
|
schemaId s,
|
|
";\n\n",
|
|
concatMap show (schemaContent s)
|
|
]
|
|
|
|
-- Helper generators
|
|
|
|
genSafeLCChar :: QC.Gen Char
|
|
genSafeLCChar = QC.elements ['a' .. 'z']
|
|
|
|
genSafeUCChar :: QC.Gen Char
|
|
genSafeUCChar = QC.elements ['A' .. 'Z']
|
|
|
|
genSafeHexChar :: QC.Gen Char
|
|
genSafeHexChar = QC.elements (['0' .. '9'] ++ ['a' .. 'f'])
|
|
|
|
newtype FieldGen a
|
|
= FieldGen (StateT (NonEmpty (Int, Int)) QC.Gen a)
|
|
deriving (Functor, Applicative, Monad)
|
|
|
|
liftGen :: QC.Gen a -> FieldGen a
|
|
liftGen m = FieldGen (lift m)
|
|
|
|
runFieldGen :: FieldGen a -> QC.Gen a
|
|
runFieldGen (FieldGen m) = fst <$> runStateT m ((0, 0) :| [])
|
|
|
|
pushFieldGen :: FieldGen ()
|
|
pushFieldGen = FieldGen $ modify (NE.cons (0, 0))
|
|
|
|
popFieldGen :: FieldGen ()
|
|
popFieldGen = FieldGen $ do
|
|
original <- get
|
|
case original of
|
|
(_ :| (y : rest)) -> put (y :| rest)
|
|
(x :| []) -> put (x :| [])
|
|
|
|
getStructOrder :: FieldGen Int
|
|
getStructOrder = FieldGen $ do
|
|
current <- get
|
|
let (result, _) = NE.head current
|
|
case current of
|
|
((x, y) :| rest) -> put ((x + 1, y) :| rest)
|
|
return result
|
|
|
|
getOrder :: FieldGen Int
|
|
getOrder = FieldGen $ do
|
|
current <- get
|
|
let (_, result) = NE.head current
|
|
case current of
|
|
((x, y) :| rest) -> put ((x + 1, y + 1) :| rest)
|
|
return result
|
|
|
|
-- Field types
|
|
|
|
-- need to enumerate each field; this will be performed during struct
|
|
-- generation where the number of fields is known (numberDefs)
|
|
genFieldDef :: [FieldType] -> FieldGen Field
|
|
genFieldDef structTypes = do
|
|
order <- getOrder
|
|
fieldName <- do
|
|
str <- liftGen $ QC.listOf1 genSafeLCChar
|
|
return $ FieldName (str ++ show order)
|
|
fieldType <- liftGen $ QC.elements (map BasicType [Bool ..] ++ structTypes)
|
|
return $ FieldDef fieldName order fieldType
|
|
|
|
-- Struct type
|
|
|
|
-- like fields, we enumerate each struct during generation for uniqueness
|
|
genStructDef :: Int -> FieldGen Field
|
|
genStructDef depth = do
|
|
order <- getStructOrder
|
|
|
|
pushFieldGen
|
|
|
|
-- generate the struct's name
|
|
structName <- do
|
|
fc <- liftGen genSafeUCChar
|
|
rest <- liftGen (QC.listOf genSafeLCChar)
|
|
return $ StructName ((fc : rest) ++ show order)
|
|
|
|
-- generate the nested structs
|
|
structNum <-
|
|
if depth <= 0
|
|
then pure 0
|
|
else liftGen (QC.choose (0, 3))
|
|
structDefs <- replicateM structNum (genStructDef (depth - 1))
|
|
|
|
-- extract the available struct types
|
|
let structTypes = map (\(StructDef sn _) -> StructType sn) structDefs
|
|
|
|
-- generate the fields using available struct types
|
|
fieldNum <- liftGen (QC.sized (\n -> QC.choose (1, 1 `max` n)))
|
|
fieldDefs <- replicateM fieldNum (genFieldDef structTypes)
|
|
|
|
popFieldGen
|
|
|
|
return $ StructDef structName (fieldDefs ++ structDefs)
|
|
|
|
-- Schema type
|
|
genSchema :: QC.Gen Schema
|
|
genSchema = do
|
|
id1st <- QC.elements ['a' .. 'f']
|
|
idrest <- QC.vectorOf 15 genSafeHexChar
|
|
-- multiple structs make tests take too long
|
|
content <- runFieldGen (genStructDef 3)
|
|
return $ Schema (id1st : idrest) [content]
|