canontra-0.1.0.0: src/Canontra/Canonical/Serialize.hs
{- |
Module : Canontra.Canonical.Serialize
Description : Deterministic binary serialization for normalized IR, CFGs, and DFGs.
Canonicalization transforms abstract syntax into an unambiguous byte stream.
Every constructor, collection, primitive scalar, float (IEEE-754 normalized),
Unicode string (NFC precomposed), CFG basic block, and DFG Def-Use chain is encoded
with deterministic length prefixes and explicit tag bytes.
-}
module Canontra.Canonical.Serialize
( canonicalizeProgram
, canonicalizeDeclarations
, canonicalizeDependencies
, canonicalizeRichDependencyGraph
, canonicalizeCallGraph
, canonicalizeCFGs
, canonicalizeDFGs
, canonicalizeWholeRepoCallGraph
, canonicalizeWholeRepoDataFlow
, canonicalizeModule
, canonicalizeDeclaration
, canonicalizeDeclarationStructural
, canonicalizeStmt
, canonicalizeExpr
) where
import qualified Data.ByteString as BS
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Data.Word (Word8)
import Canontra.Analysis.CallGraph
import Canontra.Analysis.CFG
import Canontra.Analysis.DFG
import Canontra.Types
( DeclKind (..)
, Fingerprint (..)
, GlobalSymbol (..)
, InterProceduralDataFlowEdge (..)
, WholeRepoCallEdge (..)
, WholeRepoCallGraph (..)
, WholeRepoDataFlowGraph (..)
)
import Canontra.Canonical.Float (encodeCanonicalFloat)
import Canontra.Canonical.Unicode (canonicalizeText)
import Canontra.IR.Declaration
import Canontra.IR.Dependency
import Canontra.IR.Expression
import Canontra.IR.Program
canonicalizeProgram :: Program -> BS.ByteString
canonicalizeProgram (Program modules lang) =
LBS.toStrict $ BB.toLazyByteString $
tag 0x01 <> encodeText lang <> encodeList canonicalizeModuleB modules
canonicalizeDeclarations :: [Declaration] -> BS.ByteString
canonicalizeDeclarations decls =
LBS.toStrict $ BB.toLazyByteString $
tag 0x02 <> encodeList canonicalizeDeclarationB decls
canonicalizeDependencies :: [ImportDecl] -> BS.ByteString
canonicalizeDependencies imps =
LBS.toStrict $ BB.toLazyByteString $
tag 0x03 <> encodeList canonicalizeImportB imps
canonicalizeRichDependencyGraph :: RichDependencyGraph -> BS.ByteString
canonicalizeRichDependencyGraph (RichDependencyGraph exts intras) =
LBS.toStrict $ BB.toLazyByteString $
tag 0x04 <>
encodeList canonicalizeResolvedImportB exts <>
encodeList (\(a, b) -> encodeText a <> encodeText b) intras
canonicalizeCallGraph :: CallGraph -> BS.ByteString
canonicalizeCallGraph (CallGraph nodes edges) =
LBS.toStrict $ BB.toLazyByteString $
tag 0x05 <>
encodeList canonicalizeCallerNodeB nodes <>
encodeList canonicalizeCallEdgeB edges
canonicalizeCFGs :: [ControlFlowGraph] -> BS.ByteString
canonicalizeCFGs cfgs =
LBS.toStrict $ BB.toLazyByteString $
tag 0x06 <> encodeList canonicalizeCFGB cfgs
canonicalizeDFGs :: [DataFlowGraph] -> BS.ByteString
canonicalizeDFGs dfgs =
LBS.toStrict $ BB.toLazyByteString $
tag 0x07 <> encodeList canonicalizeDFGB dfgs
canonicalizeWholeRepoCallGraph :: WholeRepoCallGraph -> BS.ByteString
canonicalizeWholeRepoCallGraph (WholeRepoCallGraph nodes edges sccs) =
LBS.toStrict $ BB.toLazyByteString $
tag 0x08 <>
encodeList canonicalizeGlobalSymbolB nodes <>
encodeList canonicalizeWholeRepoCallEdgeB edges <>
encodeList (encodeList canonicalizeGlobalSymbolB) sccs
canonicalizeGlobalSymbolB :: GlobalSymbol -> BB.Builder
canonicalizeGlobalSymbolB (GlobalSymbol fp modName name kind (Fingerprint f2)) =
tag 0x18 <>
encodeText (T.pack fp) <>
encodeText modName <>
encodeText name <>
encodeDeclKindB kind <>
encodeText f2
encodeDeclKindB :: DeclKind -> BB.Builder
encodeDeclKindB = \case
KindFunction -> tag 0x01
KindMethod -> tag 0x02
KindClass -> tag 0x03
KindStruct -> tag 0x04
KindInterface -> tag 0x05
KindTrait -> tag 0x06
KindImpl -> tag 0x07
KindVariable -> tag 0x08
KindTypeAlias -> tag 0x09
canonicalizeWholeRepoCallEdgeB :: WholeRepoCallEdge -> BB.Builder
canonicalizeWholeRepoCallEdgeB (WholeRepoCallEdge caller callee cnt isAsync isCross) =
tag 0x28 <>
canonicalizeGlobalSymbolB caller <>
canonicalizeGlobalSymbolB callee <>
BB.int64BE (fromIntegral cnt) <>
tag (if isAsync then 0x01 else 0x00) <>
tag (if isCross then 0x01 else 0x00)
canonicalizeWholeRepoDataFlow :: WholeRepoDataFlowGraph -> BS.ByteString
canonicalizeWholeRepoDataFlow (WholeRepoDataFlowGraph nodes edges) =
LBS.toStrict $ BB.toLazyByteString $
tag 0x09 <>
encodeList canonicalizeGlobalSymbolB nodes <>
encodeList canonicalizeInterProceduralDataFlowEdgeB edges
canonicalizeInterProceduralDataFlowEdgeB :: InterProceduralDataFlowEdge -> BB.Builder
canonicalizeInterProceduralDataFlowEdgeB (InterProceduralDataFlowEdge src tgt pIdx vName isRet) =
tag 0x38 <>
canonicalizeGlobalSymbolB src <>
canonicalizeGlobalSymbolB tgt <>
BB.int64BE (fromIntegral pIdx) <>
encodeText vName <>
tag (if isRet then 0x01 else 0x00)
canonicalizeModule :: Module -> BS.ByteString
canonicalizeModule = LBS.toStrict . BB.toLazyByteString . canonicalizeModuleB
canonicalizeModuleB :: Module -> BB.Builder
canonicalizeModuleB (Module name imps decls stmts) =
tag 0x10 <>
encodeText name <>
encodeList canonicalizeImportB imps <>
encodeList canonicalizeDeclarationStructuralB decls <>
encodeList canonicalizeStmtB stmts
canonicalizeImportB :: ImportDecl -> BB.Builder
canonicalizeImportB imp = case imp of
ImportModule modName maybeAlias ->
tag 0x20 <> encodeText modName <> encodeMaybe encodeText maybeAlias
ImportFrom modName (ImportSymbols syms) ->
tag 0x21 <> encodeText modName <> encodeList (\(s, a) -> encodeText s <> encodeMaybe encodeText a) syms
ImportFrom modName ImportAll ->
tag 0x22 <> encodeText modName
canonicalizeResolvedImportB :: ResolvedImport -> BB.Builder
canonicalizeResolvedImportB (ResolvedImport modName sym alias rel usage) =
tag 0x25 <>
encodeText modName <>
encodeMaybe encodeText sym <>
encodeMaybe encodeText alias <>
BB.int64BE (fromIntegral rel) <>
canonicalizeUsageB usage
canonicalizeUsageB :: DependencyUsage -> BB.Builder
canonicalizeUsageB = \case
DepUnused -> tag 0x26
DepDirectCall syms -> tag 0x27 <> encodeList encodeText syms
DepInheritance syms -> tag 0x28 <> encodeList encodeText syms
DepTypeOnly syms -> tag 0x29 <> encodeList encodeText syms
DepValueRef syms -> tag 0x2A <> encodeList encodeText syms
canonicalizeCallerNodeB :: CallerNode -> BB.Builder
canonicalizeCallerNodeB = \case
CallTopLevel -> tag 0x01
CallFunction fn -> tag 0x02 <> encodeText fn
CallMethod cls m -> tag 0x03 <> encodeText cls <> encodeText m
canonicalizeCalleeTargetB :: CalleeTarget -> BB.Builder
canonicalizeCalleeTargetB = \case
TargetLocal name -> tag 0x01 <> encodeText name
TargetMethod cls m -> tag 0x02 <> encodeText cls <> encodeText m
TargetImported mod' s -> tag 0x03 <> encodeText mod' <> encodeText s
TargetDynamic expr -> tag 0x04 <> canonicalizeExprB expr
canonicalizeCallEdgeB :: CallEdge -> BB.Builder
canonicalizeCallEdgeB (CallEdge caller callee cnt isAsync) =
canonicalizeCallerNodeB caller <>
canonicalizeCalleeTargetB callee <>
BB.int64BE (fromIntegral cnt) <>
(if isAsync then tag 0x01 else tag 0x00)
-- | Serializer for Control-Flow Graphs
canonicalizeCFGB :: ControlFlowGraph -> BB.Builder
canonicalizeCFGB (ControlFlowGraph fn entry blocks edges) =
encodeText fn <>
BB.int64BE (fromIntegral entry) <>
encodeList canonicalizeBasicBlockB blocks <>
encodeList canonicalizeCFGEdgeB edges
canonicalizeBasicBlockB :: BasicBlock -> BB.Builder
canonicalizeBasicBlockB (BasicBlock bId stmts term) =
BB.int64BE (fromIntegral bId) <>
encodeList canonicalizeStmtB stmts <>
canonicalizeTerminatorB term
canonicalizeTerminatorB :: BlockTerminator -> BB.Builder
canonicalizeTerminatorB = \case
TermReturn me -> tag 0x01 <> encodeMaybe canonicalizeExprB me
TermBranch c t f -> tag 0x02 <> canonicalizeExprB c <> BB.int64BE (fromIntegral t) <> BB.int64BE (fromIntegral f)
TermJump j -> tag 0x03 <> BB.int64BE (fromIntegral j)
TermSwitch e cases mDef -> tag 0x04 <> canonicalizeExprB e <> encodeList (\(p, b) -> canonicalizeExprB p <> BB.int64BE (fromIntegral b)) cases <> encodeMaybe (BB.int64BE . fromIntegral) mDef
TermRaise me -> tag 0x05 <> encodeMaybe canonicalizeExprB me
TermExit -> tag 0x06
canonicalizeCFGEdgeB :: CFGEdge -> BB.Builder
canonicalizeCFGEdgeB (CFGEdge fromB toB cond) =
BB.int64BE (fromIntegral fromB) <>
BB.int64BE (fromIntegral toB) <>
canonicalizeBranchCondB cond
canonicalizeBranchCondB :: BranchCondition -> BB.Builder
canonicalizeBranchCondB = \case
CondTrue e -> tag 0x01 <> canonicalizeExprB e
CondFalse e -> tag 0x02 <> canonicalizeExprB e
CondCase e -> tag 0x03 <> canonicalizeExprB e
CondDefault -> tag 0x04
CondUnconditional -> tag 0x05
CondException ex -> tag 0x06 <> encodeText ex
-- | Serializer for Data-Flow Graphs
canonicalizeDFGB :: DataFlowGraph -> BB.Builder
canonicalizeDFGB (DataFlowGraph fn nodes edges) =
encodeText fn <>
encodeList canonicalizeDFGNodeB nodes <>
encodeList canonicalizeDFGEdgeB edges
canonicalizeDFGNodeB :: DFGNode -> BB.Builder
canonicalizeDFGNodeB (DFGNode nId kind expr) =
BB.int64BE (fromIntegral nId) <>
canonicalizeDefUseKindB kind <>
encodeMaybe canonicalizeExprB expr
canonicalizeDefUseKindB :: DefUseKind -> BB.Builder
canonicalizeDefUseKindB = \case
DefParam idx -> tag 0x01 <> BB.int64BE (fromIntegral idx)
DefAssignment v -> tag 0x02 <> encodeText v
DefPhi nodeIds -> tag 0x03 <> encodeList (BB.int64BE . fromIntegral) nodeIds
UseRead v -> tag 0x04 <> encodeText v
UseArgument idx -> tag 0x05 <> BB.int64BE (fromIntegral idx)
UseBranchGuard -> tag 0x06
canonicalizeDFGEdgeB :: DFGEdge -> BB.Builder
canonicalizeDFGEdgeB (DFGEdge src tgt var) =
BB.int64BE (fromIntegral src) <>
BB.int64BE (fromIntegral tgt) <>
encodeText var
canonicalizeDeclaration :: Declaration -> BS.ByteString
canonicalizeDeclaration = LBS.toStrict . BB.toLazyByteString . canonicalizeDeclarationB
canonicalizeDeclarationStructural :: Declaration -> BS.ByteString
canonicalizeDeclarationStructural = LBS.toStrict . BB.toLazyByteString . canonicalizeDeclarationStructuralB
canonicalizeDeclarationB :: Declaration -> BB.Builder
canonicalizeDeclarationB decl = case decl of
DeclFunction (Function name params retType decs _ isAsync) ->
tag 0x30 <>
encodeText name <>
encodeList canonicalizeParamB params <>
encodeMaybe encodeText retType <>
encodeList encodeText decs <>
(if isAsync then tag 0x01 else tag 0x00)
DeclClass (Class name bases methods decs) ->
tag 0x31 <>
encodeText name <>
encodeList encodeText bases <>
encodeList canonicalizeDeclarationB [DeclFunction m | m <- methods] <>
encodeList encodeText decs
DeclStruct (Struct name fields methods vis) ->
tag 0x32 <>
encodeText name <>
encodeList (\(f, t) -> encodeText f <> encodeMaybe encodeText t) fields <>
encodeList canonicalizeDeclarationB [DeclFunction m | m <- methods] <>
encodeText vis
DeclInterface (Interface name methods bases) ->
tag 0x33 <>
encodeText name <>
encodeList canonicalizeDeclarationB [DeclFunction m | m <- methods] <>
encodeList encodeText bases
DeclReceiver (Receiver var ty ptr) fn ->
tag 0x34 <>
encodeText var <> encodeText ty <> (if ptr then tag 0x01 else tag 0x00) <>
canonicalizeDeclarationB (DeclFunction fn)
DeclTrait (Trait name methods superTrs) ->
tag 0x35 <>
encodeText name <>
encodeList canonicalizeDeclarationB [DeclFunction m | m <- methods] <>
encodeList encodeText superTrs
DeclImpl (Impl mTr tgt methods) ->
tag 0x36 <>
encodeMaybe encodeText mTr <>
encodeText tgt <>
encodeList canonicalizeDeclarationB [DeclFunction m | m <- methods]
DeclVariable varName maybeType ->
tag 0x37 <> encodeText varName <> encodeMaybe encodeText maybeType
DeclTypeAlias aliasName origType ->
tag 0x38 <> encodeText aliasName <> encodeMaybe encodeText origType
canonicalizeDeclarationStructuralB :: Declaration -> BB.Builder
canonicalizeDeclarationStructuralB decl = case decl of
DeclFunction (Function name params retType decs body isAsync) ->
tag 0x30 <>
encodeText name <>
encodeList canonicalizeParamB params <>
encodeMaybe encodeText retType <>
encodeList encodeText decs <>
encodeList canonicalizeStmtB body <>
(if isAsync then tag 0x01 else tag 0x00)
DeclClass (Class name bases methods decs) ->
tag 0x31 <>
encodeText name <>
encodeList encodeText bases <>
encodeList canonicalizeDeclarationStructuralB [DeclFunction m | m <- methods] <>
encodeList encodeText decs
DeclStruct (Struct name fields methods vis) ->
tag 0x32 <>
encodeText name <>
encodeList (\(f, t) -> encodeText f <> encodeMaybe encodeText t) fields <>
encodeList canonicalizeDeclarationStructuralB [DeclFunction m | m <- methods] <>
encodeText vis
DeclInterface (Interface name methods bases) ->
tag 0x33 <>
encodeText name <>
encodeList canonicalizeDeclarationStructuralB [DeclFunction m | m <- methods] <>
encodeList encodeText bases
DeclReceiver (Receiver var ty ptr) fn ->
tag 0x34 <>
encodeText var <> encodeText ty <> (if ptr then tag 0x01 else tag 0x00) <>
canonicalizeDeclarationStructuralB (DeclFunction fn)
DeclTrait (Trait name methods superTrs) ->
tag 0x35 <>
encodeText name <>
encodeList canonicalizeDeclarationStructuralB [DeclFunction m | m <- methods] <>
encodeList encodeText superTrs
DeclImpl (Impl mTr tgt methods) ->
tag 0x36 <>
encodeMaybe encodeText mTr <>
encodeText tgt <>
encodeList canonicalizeDeclarationStructuralB [DeclFunction m | m <- methods]
DeclVariable varName maybeType ->
tag 0x37 <> encodeText varName <> encodeMaybe encodeText maybeType
DeclTypeAlias aliasName origType ->
tag 0x38 <> encodeText aliasName <> encodeMaybe encodeText origType
canonicalizeParamB :: Parameter -> BB.Builder
canonicalizeParamB (Parameter name kind defVal mType) =
encodeText name <>
tag (paramKindTag kind) <>
encodeMaybe encodeText defVal <>
encodeMaybe encodeText mType
paramKindTag :: ParamKind -> Word8
paramKindTag = \case
ParamPositional -> 0x01
ParamKeywordOnly -> 0x02
ParamVarArgs -> 0x03
ParamKwArgs -> 0x04
ParamPositionalOnly -> 0x05
canonicalizeStmt :: Stmt -> BS.ByteString
canonicalizeStmt = LBS.toStrict . BB.toLazyByteString . canonicalizeStmtB
canonicalizeStmtB :: Stmt -> BB.Builder
canonicalizeStmtB stmt = case stmt of
StmtAssign targets expr ->
tag 0x40 <> encodeList canonicalizeExprB targets <> canonicalizeExprB expr
StmtAugAssign target op expr ->
tag 0x41 <> canonicalizeExprB target <> tag (opTag op) <> canonicalizeExprB expr
StmtExpr expr ->
tag 0x42 <> canonicalizeExprB expr
StmtReturn maybeExpr ->
tag 0x43 <> encodeMaybe canonicalizeExprB maybeExpr
StmtIf cond body elseSuite ->
tag 0x44 <> canonicalizeExprB cond <> encodeList canonicalizeStmtB body <> encodeList canonicalizeStmtB elseSuite
StmtWhile cond body elseSuite ->
tag 0x45 <> canonicalizeExprB cond <> encodeList canonicalizeStmtB body <> encodeList canonicalizeStmtB elseSuite
StmtFor target iter body elseSuite ->
tag 0x46 <> canonicalizeExprB target <> canonicalizeExprB iter <> encodeList canonicalizeStmtB body <> encodeList canonicalizeStmtB elseSuite
StmtTry body handlers elseSuite finalSuite ->
tag 0x47 <> encodeList canonicalizeStmtB body <>
encodeList (\(c, a, b) -> encodeMaybe canonicalizeExprB c <> encodeMaybe encodeText a <> encodeList canonicalizeStmtB b) handlers <>
encodeList canonicalizeStmtB elseSuite <> encodeList canonicalizeStmtB finalSuite
StmtWith items body ->
tag 0x48 <> encodeList (\(e, a) -> canonicalizeExprB e <> encodeMaybe canonicalizeExprB a) items <> encodeList canonicalizeStmtB body
StmtAssert expr maybeMsg ->
tag 0x49 <> canonicalizeExprB expr <> encodeMaybe canonicalizeExprB maybeMsg
StmtRaise maybeExpr maybeCause ->
tag 0x4A <> encodeMaybe canonicalizeExprB maybeExpr <> encodeMaybe canonicalizeExprB maybeCause
StmtBreak -> tag 0x4B
StmtContinue -> tag 0x4C
StmtPass -> tag 0x4D
StmtDelete exprs -> tag 0x4E <> encodeList canonicalizeExprB exprs
StmtGlobal vars -> tag 0x4F <> encodeList encodeText vars
StmtNonlocal vars -> tag 0x50 <> encodeList encodeText vars
StmtAnnAssign target ty maybeVal ->
tag 0x51 <> canonicalizeExprB target <> canonicalizeExprB ty <> encodeMaybe canonicalizeExprB maybeVal
StmtAsyncFor target iter body elseSuite ->
tag 0x52 <> canonicalizeExprB target <> canonicalizeExprB iter <> encodeList canonicalizeStmtB body <> encodeList canonicalizeStmtB elseSuite
StmtAsyncWith items body ->
tag 0x53 <> encodeList (\(e, a) -> canonicalizeExprB e <> encodeMaybe canonicalizeExprB a) items <> encodeList canonicalizeStmtB body
StmtMatch expr cases ->
tag 0x54 <> canonicalizeExprB expr <> encodeList canonicalizeMatchCaseB cases
StmtGo expr ->
tag 0x55 <> canonicalizeExprB expr
StmtDefer expr ->
tag 0x56 <> canonicalizeExprB expr
StmtChanSend ch val ->
tag 0x57 <> canonicalizeExprB ch <> canonicalizeExprB val
StmtSelect cases ->
tag 0x58 <> encodeList (\(sc, b) -> canonicalizeSelectCaseB sc <> encodeList canonicalizeStmtB b) cases
StmtLoop body ->
tag 0x59 <> encodeList canonicalizeStmtB body
StmtSwitch expr cases defStmts ->
tag 0x5A <> canonicalizeExprB expr <> encodeList (\(c, b) -> canonicalizeExprB c <> encodeList canonicalizeStmtB b) cases <> encodeList canonicalizeStmtB defStmts
canonicalizeSelectCaseB :: SelectCase -> BB.Builder
canonicalizeSelectCaseB = \case
SelectSend ch val -> tag 0x01 <> canonicalizeExprB ch <> canonicalizeExprB val
SelectRecv mV ch -> tag 0x02 <> encodeMaybe encodeText mV <> canonicalizeExprB ch
SelectDefault -> tag 0x03
canonicalizeMatchCaseB :: MatchCase -> BB.Builder
canonicalizeMatchCaseB (MatchCase pat guard body) =
canonicalizeExprB pat <> encodeMaybe canonicalizeExprB guard <> encodeList canonicalizeStmtB body
canonicalizeExpr :: Expr -> BS.ByteString
canonicalizeExpr = LBS.toStrict . BB.toLazyByteString . canonicalizeExprB
canonicalizeExprB :: Expr -> BB.Builder
canonicalizeExprB expr = case expr of
ExprId ident -> tag 0x60 <> encodeText ident
ExprLit lit -> tag 0x61 <> canonicalizeLitB lit
ExprBinary op e1 e2 -> tag 0x62 <> tag (opTag op) <> canonicalizeExprB e1 <> canonicalizeExprB e2
ExprUnary op e -> tag 0x63 <> tag (opTag op) <> canonicalizeExprB e
ExprCall target args kwArgs ->
tag 0x64 <> canonicalizeExprB target <> encodeList canonicalizeExprB args <> encodeList (\(k, v) -> encodeText k <> canonicalizeExprB v) kwArgs
ExprAttr target attr -> tag 0x65 <> canonicalizeExprB target <> encodeText attr
ExprSubscript target idx -> tag 0x66 <> canonicalizeExprB target <> canonicalizeExprB idx
ExprList items -> tag 0x67 <> encodeList canonicalizeExprB items
ExprTuple items -> tag 0x68 <> encodeList canonicalizeExprB items
ExprDict items -> tag 0x69 <> encodeList (\(k, v) -> canonicalizeExprB k <> canonicalizeExprB v) items
ExprSet items -> tag 0x6A <> encodeList canonicalizeExprB items
ExprLambda params body -> tag 0x6B <> encodeList canonicalizeParamB params <> canonicalizeExprB body
ExprTernary cond t f -> tag 0x6C <> canonicalizeExprB cond <> canonicalizeExprB t <> canonicalizeExprB f
ExprListComp item comps -> tag 0x6D <> canonicalizeExprB item <> encodeList canonicalizeCompB comps
ExprDictComp k v comps -> tag 0x6E <> canonicalizeExprB k <> canonicalizeExprB v <> encodeList canonicalizeCompB comps
ExprGenerator item comps -> tag 0x6F <> canonicalizeExprB item <> encodeList canonicalizeCompB comps
ExprSetComp item comps -> tag 0x80 <> canonicalizeExprB item <> encodeList canonicalizeCompB comps
ExprWalrus name val -> tag 0x81 <> encodeText name <> canonicalizeExprB val
ExprAwait e -> tag 0x82 <> canonicalizeExprB e
ExprYield me -> tag 0x83 <> encodeMaybe canonicalizeExprB me
ExprYieldFrom e -> tag 0x84 <> canonicalizeExprB e
ExprFormattedString parts -> tag 0x85 <> encodeList canonicalizeFStringPartB parts
ExprStarred e -> tag 0x86 <> canonicalizeExprB e
ExprKwStarred e -> tag 0x87 <> canonicalizeExprB e
ExprSlice ms me mst -> tag 0x88 <> encodeMaybe canonicalizeExprB ms <> encodeMaybe canonicalizeExprB me <> encodeMaybe canonicalizeExprB mst
ExprOptChain e prop -> tag 0x89 <> canonicalizeExprB e <> encodeText prop
ExprNullish e1 e2 -> tag 0x8A <> canonicalizeExprB e1 <> canonicalizeExprB e2
ExprChanRecv ch -> tag 0x8B <> canonicalizeExprB ch
ExprTryOp e -> tag 0x8C <> canonicalizeExprB e
ExprMacroCall name args -> tag 0x8D <> encodeText name <> encodeList canonicalizeExprB args
ExprJSX tagElem attrs children ->
tag 0x8E <> encodeText tagElem <>
encodeList (\(k, v) -> encodeText k <> canonicalizeExprB v) attrs <>
encodeList canonicalizeExprB children
canonicalizeFStringPartB :: FStringPart -> BB.Builder
canonicalizeFStringPartB = \case
FStringText t -> tag 0x01 <> encodeText t
FStringExpr e conv fmt -> tag 0x02 <> canonicalizeExprB e <> encodeMaybe encodeText conv <> encodeMaybe encodeText fmt
canonicalizeLitB :: Lit -> BB.Builder
canonicalizeLitB lit = case lit of
LitInt n -> tag 0x70 <> BB.integerDec n
LitFloat f -> tag 0x71 <> BB.byteString (encodeCanonicalFloat f)
LitString s -> tag 0x72 <> encodeText s
LitBytes b -> tag 0x73 <> encodeText b
LitBool True -> tag 0x74
LitBool False-> tag 0x75
LitNone -> tag 0x76
LitEllipsis -> tag 0x77
canonicalizeCompB :: CompFor -> BB.Builder
canonicalizeCompB (CompFor target iter ifs) =
canonicalizeExprB target <> canonicalizeExprB iter <> encodeList canonicalizeExprB ifs
opTag :: Op -> Word8
opTag = \case
OpAdd -> 0x01; OpSub -> 0x02; OpMul -> 0x03; OpDiv -> 0x04; OpFloorDiv -> 0x05; OpMod -> 0x06; OpPow -> 0x07
OpBitAnd -> 0x08; OpBitOr -> 0x09; OpBitXor -> 0x0A; OpShiftL -> 0x0B; OpShiftR -> 0x0C
OpEq -> 0x0D; OpNotEq -> 0x0E; OpLt -> 0x0F; OpLtE -> 0x10; OpGt -> 0x11; OpGtE -> 0x12
OpAnd -> 0x13; OpOr -> 0x14; OpNot -> 0x15; OpInvert -> 0x16; OpIn -> 0x17; OpNotIn -> 0x18; OpIs -> 0x19; OpIsNot -> 0x1A
OpMatMult -> 0x1B
tag :: Word8 -> BB.Builder
tag = BB.word8
encodeText :: T.Text -> BB.Builder
encodeText t =
let canonicalT = canonicalizeText t
bs = TE.encodeUtf8 canonicalT
in BB.int64BE (fromIntegral (BS.length bs)) <> BB.byteString bs
encodeList :: (a -> BB.Builder) -> [a] -> BB.Builder
encodeList itemSerializer xs =
BB.int64BE (fromIntegral (length xs)) <> mconcat (map itemSerializer xs)
encodeMaybe :: (a -> BB.Builder) -> Maybe a -> BB.Builder
encodeMaybe _ Nothing = tag 0x00
encodeMaybe itemSerializer (Just x) = tag 0x01 <> itemSerializer x