Full Arboricx parsing in tricu
This commit is contained in:
432
lib/arboricx-common.tri
Normal file
432
lib/arboricx-common.tri
Normal file
@@ -0,0 +1,432 @@
|
||||
!import "base.tri" !Local
|
||||
!import "list.tri" !Local
|
||||
!import "bytes.tri" !Local
|
||||
!import "binary.tri" !Local
|
||||
|
||||
arboricxMagic = [(65) (82) (66) (79) (82) (73) (67) (88)]
|
||||
arboricxMajorVersion = [(0) (1)]
|
||||
arboricxMinorVersion = [(0) (0)]
|
||||
arboricxManifestSectionId = [(0) (0) (0) (1)]
|
||||
arboricxNodesSectionId = [(0) (0) (0) (2)]
|
||||
|
||||
-- Manifest magic and version constants
|
||||
arboricxManifestMagic = [(65) (82) (66) (77) (78) (70) (83) (84)]
|
||||
arboricxManifestMajorVersion = [(0) (1)]
|
||||
arboricxManifestMinorVersion = [(0) (0)]
|
||||
|
||||
errMissingSection = 4
|
||||
errUnsupportedVersion = 5
|
||||
errDuplicateSection = 6
|
||||
errDuplicateNode = 7
|
||||
errInvalidNodePayload = 8
|
||||
errMissingNode = 9
|
||||
errInvalidManifestMagic = 10
|
||||
errUnsupportedManifestVersion = 11
|
||||
errTrailingManifestBytes = 12
|
||||
errManifestValidationFailed = 13
|
||||
|
||||
nodePayloadLeafTag = 0
|
||||
nodePayloadStemTag = 1
|
||||
nodePayloadForkTag = 2
|
||||
|
||||
readArboricxMagic = (bs : expectBytes arboricxMagic bs)
|
||||
|
||||
readArboricxHeader = (bs :
|
||||
bindResult (readArboricxMagic bs)
|
||||
(_ afterMagic :
|
||||
bindResult (readBytes 2 afterMagic)
|
||||
(majorVersion afterMajor :
|
||||
bindResult (readBytes 2 afterMajor)
|
||||
(minorVersion afterMinor :
|
||||
bindResult (readBytes 4 afterMinor)
|
||||
(sectionCount afterSectionCount :
|
||||
bindResult (readBytes 8 afterSectionCount)
|
||||
(flags afterFlags :
|
||||
bindResult (readBytes 8 afterFlags)
|
||||
(dirOffset afterDirOffset :
|
||||
ok
|
||||
(pair majorVersion
|
||||
(pair minorVersion
|
||||
(pair sectionCount
|
||||
(pair flags dirOffset))))
|
||||
afterDirOffset)))))))
|
||||
|
||||
readSectionRecord = (bs :
|
||||
bindResult (readBytes 4 bs)
|
||||
(sectionId afterSectionId :
|
||||
bindResult (readBytes 2 afterSectionId)
|
||||
(sectionVersion afterSectionVersion :
|
||||
bindResult (readBytes 2 afterSectionVersion)
|
||||
(sectionFlags afterSectionFlags :
|
||||
bindResult (readBytes 2 afterSectionFlags)
|
||||
(compression afterCompression :
|
||||
bindResult (readBytes 2 afterCompression)
|
||||
(digestAlgorithm afterDigestAlgorithm :
|
||||
bindResult (readBytes 8 afterDigestAlgorithm)
|
||||
(offset afterOffset :
|
||||
bindResult (readBytes 8 afterOffset)
|
||||
(length afterLength :
|
||||
bindResult (readBytes 32 afterLength)
|
||||
(digest afterDigest :
|
||||
ok
|
||||
(pair sectionId
|
||||
(pair sectionVersion
|
||||
(pair sectionFlags
|
||||
(pair compression
|
||||
(pair digestAlgorithm
|
||||
(pair offset
|
||||
(pair length digest)))))))
|
||||
afterDigest)))))))))
|
||||
|
||||
readSectionDirectory_ = y (self bs sectionCount i acc :
|
||||
matchBool
|
||||
(ok (reverse acc) bs)
|
||||
(bindResult (readSectionRecord bs)
|
||||
(sectionRecord afterSectionRecord :
|
||||
self afterSectionRecord sectionCount (succ i) (pair sectionRecord acc)))
|
||||
(equal? i sectionCount))
|
||||
|
||||
readSectionDirectory = (sectionCount bs : readSectionDirectory_ bs sectionCount 0 t)
|
||||
|
||||
sectionRecordId = (sectionRecord :
|
||||
matchPair
|
||||
(sectionId _ : sectionId)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordVersion = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(sectionVersion _ : sectionVersion)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordFlags = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(sectionFlags _ : sectionFlags)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordCompression = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(compression _ : compression)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordDigestAlgorithm = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ payload4 :
|
||||
matchPair
|
||||
(digestAlgorithm _ : digestAlgorithm)
|
||||
payload4)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordOffset = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ payload4 :
|
||||
matchPair
|
||||
(_ payload5 :
|
||||
matchPair
|
||||
(offset _ : offset)
|
||||
payload5)
|
||||
payload4)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordLength = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ payload4 :
|
||||
matchPair
|
||||
(_ payload5 :
|
||||
matchPair
|
||||
(_ payload6 :
|
||||
matchPair
|
||||
(length _ : length)
|
||||
payload6)
|
||||
payload5)
|
||||
payload4)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordDigest = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ payload4 :
|
||||
matchPair
|
||||
(_ payload5 :
|
||||
matchPair
|
||||
(_ payload6 :
|
||||
matchPair
|
||||
(_ digest : digest)
|
||||
payload6)
|
||||
payload5)
|
||||
payload4)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
lookupSectionRecord_ = y (self directory sectionId :
|
||||
matchList
|
||||
nothing
|
||||
(sectionRecord rest :
|
||||
matchBool
|
||||
(just sectionRecord)
|
||||
(self rest sectionId)
|
||||
(bytesEq? sectionId (sectionRecordId sectionRecord)))
|
||||
directory)
|
||||
|
||||
lookupSectionRecord = (sectionId directory : lookupSectionRecord_ directory sectionId)
|
||||
|
||||
sectionDirectoryHasId?_ = y (self directory sectionId :
|
||||
matchList
|
||||
false
|
||||
(sectionRecord rest :
|
||||
or?
|
||||
(bytesEq? sectionId (sectionRecordId sectionRecord))
|
||||
(self rest sectionId))
|
||||
directory)
|
||||
|
||||
sectionDirectoryHasId? = (sectionId directory : sectionDirectoryHasId?_ directory sectionId)
|
||||
|
||||
sectionDirectoryHasDuplicateIds? = y (self directory :
|
||||
matchList
|
||||
false
|
||||
(sectionRecord rest :
|
||||
or?
|
||||
(sectionDirectoryHasId?_ rest (sectionRecordId sectionRecord))
|
||||
(self rest))
|
||||
directory)
|
||||
|
||||
validateSectionDirectory = (directory rest :
|
||||
matchBool
|
||||
(err errDuplicateSection rest)
|
||||
(ok directory rest)
|
||||
(sectionDirectoryHasDuplicateIds? directory))
|
||||
|
||||
byteSlice = (offset length bytes : bytesTake length (bytesDrop offset bytes))
|
||||
|
||||
natMake = (bit rest :
|
||||
matchBool
|
||||
0
|
||||
(pair bit rest)
|
||||
(and? (equal? bit 0) (equal? rest 0)))
|
||||
|
||||
natAdd = y (self a b :
|
||||
triage
|
||||
b
|
||||
(_ : b)
|
||||
(aBit aRest :
|
||||
triage
|
||||
a
|
||||
(_ : a)
|
||||
(bBit bRest :
|
||||
matchBool
|
||||
(natMake 0 (succ (self aRest bRest)))
|
||||
(natMake (matchBool (matchBool 0 1 bBit) (matchBool 1 0 bBit) aBit)
|
||||
(self aRest bRest))
|
||||
(and? (equal? aBit 1) (equal? bBit 1)))
|
||||
b)
|
||||
a)
|
||||
|
||||
natDouble = (n : matchBool 0 (pair 0 n) (equal? n 0))
|
||||
|
||||
natTimes256 = (n :
|
||||
natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble n))))))))
|
||||
|
||||
byteNatShiftAppend_ = y (self byte acc i :
|
||||
matchBool
|
||||
acc
|
||||
(triage
|
||||
(natMake 0 (self 0 acc (succ i)))
|
||||
(_ : acc)
|
||||
(bit rest : natMake bit (self rest acc (succ i)))
|
||||
byte)
|
||||
(equal? i 8))
|
||||
|
||||
byteNatShiftAppend = (byte acc : byteNatShiftAppend_ byte acc 0)
|
||||
|
||||
beBytesToNat = (bytes :
|
||||
foldl
|
||||
(acc byte : byteNatShiftAppend byte acc)
|
||||
0
|
||||
bytes)
|
||||
|
||||
u32BEBytesToNat = beBytesToNat
|
||||
u64BEBytesToNat = beBytesToNat
|
||||
|
||||
arboricxHeaderMajorVersion = (header :
|
||||
matchPair
|
||||
(majorVersion _ : majorVersion)
|
||||
header)
|
||||
|
||||
arboricxHeaderMinorVersion = (header :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(minorVersion _ : minorVersion)
|
||||
payload)
|
||||
header)
|
||||
|
||||
arboricxHeaderSectionCount = (header :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(sectionCount _ : sectionCount)
|
||||
payload2)
|
||||
payload)
|
||||
header)
|
||||
|
||||
arboricxHeaderFlags = (header :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(flags _ : flags)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
header)
|
||||
|
||||
arboricxHeaderDirOffset = (header :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ dirOffset : dirOffset)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
header)
|
||||
|
||||
validateArboricxHeader = (header rest :
|
||||
matchBool
|
||||
(ok header rest)
|
||||
(err errUnsupportedVersion rest)
|
||||
(and?
|
||||
(bytesEq? arboricxMajorVersion (arboricxHeaderMajorVersion header))
|
||||
(bytesEq? arboricxMinorVersion (arboricxHeaderMinorVersion header))))
|
||||
|
||||
readArboricxContainer = (bs :
|
||||
bindResult (readArboricxHeader bs)
|
||||
(header afterHeader :
|
||||
bindResult (validateArboricxHeader header afterHeader)
|
||||
(validHeader afterValidHeader :
|
||||
bindResult (readSectionDirectory
|
||||
(u32BEBytesToNat (arboricxHeaderSectionCount validHeader))
|
||||
(bytesDrop (u64BEBytesToNat (arboricxHeaderDirOffset validHeader)) bs))
|
||||
(directory afterDirectory :
|
||||
bindResult (validateSectionDirectory directory afterDirectory)
|
||||
(validDirectory afterValidDirectory :
|
||||
ok (pair validHeader validDirectory) afterValidDirectory)))))
|
||||
|
||||
sectionRecordOffsetNat = (sectionRecord :
|
||||
u64BEBytesToNat (sectionRecordOffset sectionRecord))
|
||||
|
||||
sectionRecordLengthNat = (sectionRecord :
|
||||
u64BEBytesToNat (sectionRecordLength sectionRecord))
|
||||
|
||||
extractSectionBytes = (sectionRecord containerBytes :
|
||||
byteSlice
|
||||
(sectionRecordOffsetNat sectionRecord)
|
||||
(sectionRecordLengthNat sectionRecord)
|
||||
containerBytes)
|
||||
|
||||
extractSectionBytesResult = (sectionRecord containerBytes rest :
|
||||
(sectionBytes :
|
||||
matchBool
|
||||
(ok sectionBytes rest)
|
||||
(err errUnexpectedEof rest)
|
||||
(equal? (bytesLength sectionBytes) (sectionRecordLengthNat sectionRecord)))
|
||||
(extractSectionBytes sectionRecord containerBytes))
|
||||
|
||||
lookupSectionBytes = (sectionId directory containerBytes :
|
||||
triage
|
||||
nothing
|
||||
(sectionRecord : just (extractSectionBytes sectionRecord containerBytes))
|
||||
(_ _ : nothing)
|
||||
(lookupSectionRecord sectionId directory))
|
||||
|
||||
sectionBytesOrErr = (sectionId directory containerBytes rest :
|
||||
triage
|
||||
(err errMissingSection rest)
|
||||
(sectionRecord : extractSectionBytesResult sectionRecord containerBytes rest)
|
||||
(_ _ : err errMissingSection rest)
|
||||
(lookupSectionRecord sectionId directory))
|
||||
|
||||
readArboricxSectionBytes = (sectionId bs :
|
||||
bindResult (readArboricxContainer bs)
|
||||
(container afterContainer :
|
||||
matchPair
|
||||
(_ directory : sectionBytesOrErr sectionId directory bs afterContainer)
|
||||
container))
|
||||
|
||||
readArboricxRequiredSections = (bs :
|
||||
bindResult (readArboricxContainer bs)
|
||||
(container afterContainer :
|
||||
matchPair
|
||||
(_ directory :
|
||||
bindResult (sectionBytesOrErr arboricxManifestSectionId directory bs afterContainer)
|
||||
(manifestBytes _ :
|
||||
bindResult (sectionBytesOrErr arboricxNodesSectionId directory bs afterContainer)
|
||||
(nodesBytes _ :
|
||||
ok (pair manifestBytes nodesBytes) afterContainer)))
|
||||
container))
|
||||
339
lib/arboricx-manifest.tri
Normal file
339
lib/arboricx-manifest.tri
Normal file
@@ -0,0 +1,339 @@
|
||||
!import "arboricx-nodes.tri" !Local
|
||||
|
||||
readManifestMagic = (bs :
|
||||
expectBytes arboricxManifestMagic bs)
|
||||
|
||||
-- Read a u32 BE length, then that many raw bytes.
|
||||
-- Returns the payload bytes and remaining input.
|
||||
readLengthPrefixedString = (bs :
|
||||
bindResult (readBytes 4 bs)
|
||||
(lengthBytes afterLengthBytes :
|
||||
bindResult (readBytes (u32BEBytesToNat lengthBytes) afterLengthBytes)
|
||||
(payload afterPayload :
|
||||
ok payload afterPayload)))
|
||||
|
||||
-- Helper: read a single capability string (length-prefixed string)
|
||||
readCapability = (bs :
|
||||
readLengthPrefixedString bs)
|
||||
|
||||
-- Helper worker: read N capability strings (counts up from 0)
|
||||
readCapabilities_ = y (self bs count i acc :
|
||||
matchBool
|
||||
(ok (reverse acc) bs)
|
||||
(bindResult (readCapability bs)
|
||||
(cap afterCap :
|
||||
self afterCap count (succ i) (pair cap acc)))
|
||||
(equal? i count))
|
||||
|
||||
-- Helper: read N capabilities
|
||||
readCapabilities = (count bs :
|
||||
readCapabilities_ bs count 0 t)
|
||||
|
||||
-- Helper: read a single root entry (32-byte raw hash + length-prefixed role)
|
||||
readRootEntry = (bs :
|
||||
bindResult (readBytes 32 bs)
|
||||
(hashRaw afterHash :
|
||||
bindResult (readLengthPrefixedString afterHash)
|
||||
(role afterRole :
|
||||
ok (pair hashRaw role) afterRole)))
|
||||
|
||||
-- Helper worker: read N root entries (counts up from 0)
|
||||
readRoots_ = y (self bs count i acc :
|
||||
matchBool
|
||||
(ok (reverse acc) bs)
|
||||
(bindResult (readRootEntry bs)
|
||||
(root afterRoot :
|
||||
self afterRoot count (succ i) (pair root acc)))
|
||||
(equal? i count))
|
||||
|
||||
-- Helper: read N roots
|
||||
readRoots = (count bs :
|
||||
readRoots_ bs count 0 t)
|
||||
|
||||
-- Helper: read a single export entry
|
||||
readExportEntry = (bs :
|
||||
bindResult (readLengthPrefixedString bs)
|
||||
(name afterName :
|
||||
bindResult (readBytes 32 afterName)
|
||||
(rootHashRaw afterRootHash :
|
||||
bindResult (readLengthPrefixedString afterRootHash)
|
||||
(kind afterKind :
|
||||
bindResult (readLengthPrefixedString afterKind)
|
||||
(abi afterAbi :
|
||||
ok (pair name (pair rootHashRaw (pair kind abi))) afterAbi)))))
|
||||
|
||||
-- Helper worker: read N export entries (counts up from 0)
|
||||
readExports_ = y (self bs count i acc :
|
||||
matchBool
|
||||
(ok (reverse acc) bs)
|
||||
(bindResult (readExportEntry bs)
|
||||
(exp afterExp :
|
||||
self afterExp count (succ i) (pair exp acc)))
|
||||
(equal? i count))
|
||||
|
||||
-- Helper: read N exports
|
||||
readExports = (count bs :
|
||||
readExports_ bs count 0 t)
|
||||
|
||||
-- Main core manifest parser.
|
||||
-- Reads: magic, version, core strings, capabilities, closure, roots, exports.
|
||||
readManifestCore = (bs :
|
||||
bindResult (readManifestMagic bs)
|
||||
(_ afterMagic :
|
||||
bindResult (readBytes 2 afterMagic)
|
||||
(majorVersion afterMajor :
|
||||
bindResult (readBytes 2 afterMajor)
|
||||
(minorVersion afterMinor :
|
||||
bindResult (readLengthPrefixedString afterMinor)
|
||||
(schema afterSchema :
|
||||
bindResult (readLengthPrefixedString afterSchema)
|
||||
(bundleType afterBundleType :
|
||||
bindResult (readLengthPrefixedString afterBundleType)
|
||||
(treeCalculus afterTreeCalculus :
|
||||
bindResult (readLengthPrefixedString afterTreeCalculus)
|
||||
(treeHashAlgorithm afterTreeHashAlgorithm :
|
||||
bindResult (readLengthPrefixedString afterTreeHashAlgorithm)
|
||||
(treeHashDomain afterTreeHashDomain :
|
||||
bindResult (readLengthPrefixedString afterTreeHashDomain)
|
||||
(treeNodePayload afterTreeNodePayload :
|
||||
bindResult (readLengthPrefixedString afterTreeNodePayload)
|
||||
(runtimeSemantics afterRuntimeSemantics :
|
||||
bindResult (readLengthPrefixedString afterRuntimeSemantics)
|
||||
(runtimeEvaluation afterRuntimeEvaluation :
|
||||
bindResult (readLengthPrefixedString afterRuntimeEvaluation)
|
||||
(runtimeAbi afterRuntimeAbi :
|
||||
bindResult (readBytes 4 afterRuntimeAbi)
|
||||
(capCountRaw afterCapCountRaw :
|
||||
bindResult (readCapabilities (u32BEBytesToNat capCountRaw) afterCapCountRaw)
|
||||
(capabilities afterCapabilities :
|
||||
bindResult (readBytes 1 afterCapabilities)
|
||||
(closureByte afterClosureByte :
|
||||
bindResult (readBytes 4 afterClosureByte)
|
||||
(rootCountRaw afterRootCountRaw :
|
||||
bindResult (readRoots (u32BEBytesToNat rootCountRaw) afterRootCountRaw)
|
||||
(roots afterRoots :
|
||||
bindResult (readBytes 4 afterRoots)
|
||||
(exportCountRaw afterExportCountRaw :
|
||||
bindResult (readExports (u32BEBytesToNat exportCountRaw) afterExportCountRaw)
|
||||
(exports afterExports :
|
||||
ok
|
||||
(pair schema
|
||||
(pair bundleType
|
||||
(pair treeCalculus
|
||||
(pair treeHashAlgorithm
|
||||
(pair treeHashDomain
|
||||
(pair treeNodePayload
|
||||
(pair runtimeSemantics
|
||||
(pair runtimeEvaluation
|
||||
(pair runtimeAbi
|
||||
(pair capabilities
|
||||
(pair closureByte (pair roots exports)))))))))))) afterExports))))))))))))))))))))
|
||||
|
||||
-- Metadata tag constants (u16 values)
|
||||
tagPackage = [(0) (1)]
|
||||
tagVersion = [(0) (2)]
|
||||
tagDescription = [(0) (3)]
|
||||
tagLicense = [(0) (4)]
|
||||
tagCreatedBy = [(0) (5)]
|
||||
|
||||
-- Read a single TLV entry: u16 tag + u32 length + value bytes.
|
||||
-- Returns the pair (tag, value) and remaining input.
|
||||
readTLV = (bs :
|
||||
bindResult (readBytes 2 bs)
|
||||
(tag afterTag :
|
||||
bindResult (readBytes 4 afterTag)
|
||||
(tlvLenRaw afterTlvLenRaw :
|
||||
bindResult (readBytes (u32BEBytesToNat tlvLenRaw) afterTlvLenRaw)
|
||||
(tlvValue afterTlvValue :
|
||||
ok (pair tag tlvValue) afterTlvValue))))
|
||||
|
||||
-- Worker: read N TLV entries (counts up from 0)
|
||||
readTLVs_ = y (self bs count i acc :
|
||||
matchBool
|
||||
(ok (reverse acc) bs)
|
||||
(bindResult (readTLV bs)
|
||||
(tlv afterTlv :
|
||||
self afterTlv count (succ i) (pair tlv acc)))
|
||||
(equal? i count))
|
||||
|
||||
-- Read a count followed by that many TLV entries.
|
||||
readTLVList = (count bs :
|
||||
readTLVs_ bs count 0 t)
|
||||
|
||||
-- Skip N extension TLV entries (counts up from 0)
|
||||
skipTLVs_ = y (self bs count i :
|
||||
matchBool
|
||||
(ok unit bs)
|
||||
(bindResult (readTLV bs)
|
||||
(_ afterTlv :
|
||||
self afterTlv count (succ i)))
|
||||
(equal? i count))
|
||||
|
||||
-- Full manifest parser: core fields + metadata TLV list + extension TLV list.
|
||||
readManifest = (bs :
|
||||
bindResult (readManifestCore bs)
|
||||
(coreManifest afterCore :
|
||||
bindResult (readBytes 4 afterCore)
|
||||
(metaCountRaw afterMetaCountRaw :
|
||||
bindResult (readTLVList (u32BEBytesToNat metaCountRaw) afterMetaCountRaw)
|
||||
(metadataFields afterMetadataFields :
|
||||
bindResult (readBytes 4 afterMetadataFields)
|
||||
(extCountRaw afterExtCountRaw :
|
||||
bindResult (skipTLVs_ afterExtCountRaw (u32BEBytesToNat extCountRaw) 0)
|
||||
(afterExtensions _ :
|
||||
ok
|
||||
(pair coreManifest (pair metadataFields afterExtensions))
|
||||
afterExtensions))))))
|
||||
|
||||
-- Lookup a metadata value by tag from a TLV list.
|
||||
-- Returns nothing if not found, just value if found.
|
||||
lookupMetadata_ = y (self tlvs tag :
|
||||
matchList
|
||||
nothing
|
||||
(tlv rest :
|
||||
matchBool
|
||||
(just (matchPair (_ value : value) tlv))
|
||||
(self rest tag)
|
||||
(bytesEq? (matchPair (tlvTag _ : tlvTag) tlv) tag))
|
||||
tlvs)
|
||||
|
||||
lookupMetadata = (tlvs tag :
|
||||
lookupMetadata_ tlvs tag)
|
||||
|
||||
-- Get export name from an export entry (pair name (pair rootHash (pair kind abi)))
|
||||
exportName = (exp :
|
||||
matchPair
|
||||
(name _ : name)
|
||||
exp)
|
||||
|
||||
exportRoot = (exp :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(root _ : root)
|
||||
payload)
|
||||
exp)
|
||||
|
||||
-- Check if an export name matches a given byte string.
|
||||
exportNameEq? = (nameBytes exp :
|
||||
bytesEq? nameBytes (exportName exp))
|
||||
|
||||
-- Find first export matching a name, or nothing.
|
||||
findExportByName_ = y (self exports name :
|
||||
matchList
|
||||
nothing
|
||||
(exp rest :
|
||||
matchBool
|
||||
(just exp)
|
||||
(self rest name)
|
||||
(exportNameEq? name exp))
|
||||
exports)
|
||||
|
||||
findExportByName = (exports name :
|
||||
findExportByName_ exports name)
|
||||
|
||||
-- Get list of all export names from a list of exports.
|
||||
getExportNames_ = y (self acc exports :
|
||||
matchList
|
||||
(reverse acc)
|
||||
(exp rest :
|
||||
self (pair (exportName exp) acc) rest)
|
||||
exports)
|
||||
|
||||
getExportNames = (exports :
|
||||
getExportNames_ t exports)
|
||||
|
||||
-- Select an export: prefer explicit name, then "main", then single, then error.
|
||||
selectExport_ = y (self exports name nameBytes :
|
||||
matchBool
|
||||
-- Explicit name given
|
||||
(matchBool
|
||||
nothing
|
||||
(err errMissingSection t)
|
||||
(_ _ : nothing)
|
||||
(findExportByName exports nameBytes))
|
||||
-- No explicit name: try "main"
|
||||
(matchBool
|
||||
nothing
|
||||
(matchBool
|
||||
(equal? (length exports) 1)
|
||||
(ok (head exports) t)
|
||||
(err errMissingSection t)
|
||||
(bytesEq? (exportName (head exports)) nameBytes))
|
||||
(_ _ : nothing)
|
||||
(findExportByName exports nameBytes))
|
||||
-- Single export: auto-select
|
||||
(matchBool
|
||||
(equal? (length exports) 1)
|
||||
(ok (head exports) t)
|
||||
(err errMissingSection t)
|
||||
(emptyList? exports))
|
||||
exports)
|
||||
|
||||
selectExport = (exports nameBytes :
|
||||
selectExport_ exports nameBytes nameBytes)
|
||||
|
||||
selectExportOpt = (exports optNameBytes :
|
||||
selectExport exports optNameBytes)
|
||||
|
||||
-- Expected core string values (raw UTF-8 bytes, not decoded to Unicode characters).
|
||||
expectedSchema = "arboricx.bundle.manifest.v1"
|
||||
expectedBundleType = "tree-calculus-executable-object"
|
||||
expectedTreeCalculus = "tree-calculus.v1"
|
||||
expectedTreeHashAlgorithm = "sha256"
|
||||
expectedTreeHashDomain = "arboricx.merkle.node.v1"
|
||||
expectedTreeNodePayload = "arboricx.merkle.payload.v1"
|
||||
expectedRuntimeSemantics = "tree-calculus.v1"
|
||||
expectedRuntimeEvaluation = "normal-order"
|
||||
expectedRuntimeAbi = "arboricx.abi.tree.v1"
|
||||
|
||||
-- Manifest core field accessors.
|
||||
-- readManifestCore returns: (pair schema (pair bundleType (... (pair closureByte (pair roots exports)))))
|
||||
pairFirst = (p : matchPair (a _ : a) p)
|
||||
pairSecond = (p : matchPair (_ b : b) p)
|
||||
|
||||
manifestSchema = (core : pairFirst core)
|
||||
manifestBundleType = (core : pairFirst (pairSecond core))
|
||||
manifestTreeCalculus = (core : pairFirst (pairSecond (pairSecond core)))
|
||||
manifestTreeHashAlgorithm = (core : pairFirst (pairSecond (pairSecond (pairSecond core))))
|
||||
manifestTreeHashDomain = (core : pairFirst (pairSecond (pairSecond (pairSecond (pairSecond core)))))
|
||||
manifestTreeNodePayload = (core : pairFirst (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond core))))))
|
||||
manifestRuntimeSemantics = (core : pairFirst (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond core)))))))
|
||||
manifestRuntimeEvaluation = (core : pairFirst (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond core))))))))
|
||||
manifestRuntimeAbi = (core : pairFirst (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond core)))))))))
|
||||
manifestCapabilities = (core : pairFirst (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond core))))))))))
|
||||
manifestClosureByte = (core : pairFirst (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond core)))))))))))
|
||||
manifestRoots = (core : pairFirst (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond core))))))))))))
|
||||
manifestExports = (core : pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond (pairSecond core)))))))))))
|
||||
|
||||
-- Helper: compare a manifest field against an expected byte string.
|
||||
manifestFieldMatch? = (actual expected : bytesEq? actual expected)
|
||||
|
||||
-- Validate core manifest fields against expected values.
|
||||
validateManifestCore = (core rest :
|
||||
matchBool
|
||||
(ok core rest)
|
||||
(err errManifestValidationFailed rest)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestSchema core) expectedSchema)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestBundleType core) expectedBundleType)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestTreeCalculus core) expectedTreeCalculus)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestTreeHashAlgorithm core) expectedTreeHashAlgorithm)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestTreeHashDomain core) expectedTreeHashDomain)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestTreeNodePayload core) expectedTreeNodePayload)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestRuntimeSemantics core) expectedRuntimeSemantics)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestRuntimeEvaluation core) expectedRuntimeEvaluation)
|
||||
(and?
|
||||
(manifestFieldMatch? (manifestRuntimeAbi core) expectedRuntimeAbi)
|
||||
(and?
|
||||
(bytesEq? (manifestClosureByte core) [(0)])
|
||||
(and?
|
||||
(not? (emptyList? (manifestRoots core)))
|
||||
(not? (emptyList? (manifestExports core)))))))))))))))
|
||||
232
lib/arboricx-nodes.tri
Normal file
232
lib/arboricx-nodes.tri
Normal file
@@ -0,0 +1,232 @@
|
||||
!import "arboricx-common.tri" !Local
|
||||
|
||||
readNodeRecord = (bs :
|
||||
bindResult (readBytes 32 bs)
|
||||
(nodeHash afterNodeHash :
|
||||
bindResult (readBytes 4 afterNodeHash)
|
||||
(payloadLength afterPayloadLength :
|
||||
bindResult (readBytes (u32BEBytesToNat payloadLength) afterPayloadLength)
|
||||
(payload afterPayload :
|
||||
ok
|
||||
(pair nodeHash
|
||||
(pair payloadLength payload))
|
||||
afterPayload))))
|
||||
|
||||
nodeRecordHash = (nodeRecord :
|
||||
matchPair
|
||||
(nodeHash _ : nodeHash)
|
||||
nodeRecord)
|
||||
|
||||
nodeRecordPayloadLength = (nodeRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(payloadLength _ : payloadLength)
|
||||
payload)
|
||||
nodeRecord)
|
||||
|
||||
nodeRecordPayload = (nodeRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ nodePayload : nodePayload)
|
||||
payload)
|
||||
nodeRecord)
|
||||
|
||||
nodePayloadKind = (nodePayload : bytesHead nodePayload)
|
||||
|
||||
nodePayloadHasTag? = (tag nodePayload :
|
||||
triage
|
||||
false
|
||||
(actualTag : byteEq? actualTag tag)
|
||||
(_ _ : false)
|
||||
(nodePayloadKind nodePayload))
|
||||
|
||||
nodePayloadLeaf? = (nodePayload : bytesEq? [(0)] nodePayload)
|
||||
|
||||
nodePayloadStem? = (nodePayload :
|
||||
and?
|
||||
(nodePayloadHasTag? nodePayloadStemTag nodePayload)
|
||||
(equal? (bytesLength nodePayload) 33))
|
||||
|
||||
nodePayloadFork? = (nodePayload :
|
||||
and?
|
||||
(nodePayloadHasTag? nodePayloadForkTag nodePayload)
|
||||
(equal? (bytesLength nodePayload) 65))
|
||||
|
||||
nodePayloadValid? = (nodePayload :
|
||||
or?
|
||||
(nodePayloadLeaf? nodePayload)
|
||||
(or?
|
||||
(nodePayloadStem? nodePayload)
|
||||
(nodePayloadFork? nodePayload)))
|
||||
|
||||
nodePayloadStemChildHash = (nodePayload : bytesTake 32 (bytesDrop 1 nodePayload))
|
||||
nodePayloadForkLeftHash = (nodePayload : bytesTake 32 (bytesDrop 1 nodePayload))
|
||||
nodePayloadForkRightHash = (nodePayload : bytesTake 32 (bytesDrop 33 nodePayload))
|
||||
|
||||
nodeRecordPayloadValid? = (nodeRecord : nodePayloadValid? (nodeRecordPayload nodeRecord))
|
||||
|
||||
nodeRecordsHaveInvalidPayload? = y (self nodeRecords :
|
||||
matchList
|
||||
false
|
||||
(nodeRecord rest :
|
||||
or?
|
||||
(not? (nodeRecordPayloadValid? nodeRecord))
|
||||
(self rest))
|
||||
nodeRecords)
|
||||
|
||||
nodeRecordsHaveHash? = y (self nodeRecords nodeHash :
|
||||
matchList
|
||||
false
|
||||
(nodeRecord rest :
|
||||
or?
|
||||
(bytesEq? nodeHash (nodeRecordHash nodeRecord))
|
||||
(self rest nodeHash))
|
||||
nodeRecords)
|
||||
|
||||
nodeRecordsHaveDuplicateHashes? = y (self nodeRecords :
|
||||
matchList
|
||||
false
|
||||
(nodeRecord rest :
|
||||
or?
|
||||
(nodeRecordsHaveHash? rest (nodeRecordHash nodeRecord))
|
||||
(self rest))
|
||||
nodeRecords)
|
||||
|
||||
lookupNodeRecord_ = y (self nodeRecords nodeHash :
|
||||
matchList
|
||||
nothing
|
||||
(nodeRecord rest :
|
||||
matchBool
|
||||
(just nodeRecord)
|
||||
(self rest nodeHash)
|
||||
(bytesEq? nodeHash (nodeRecordHash nodeRecord)))
|
||||
nodeRecords)
|
||||
|
||||
lookupNodeRecord = (nodeHash nodeRecords : lookupNodeRecord_ nodeRecords nodeHash)
|
||||
|
||||
nodeRecordChildHashes = (nodeRecord :
|
||||
(nodePayload :
|
||||
matchBool
|
||||
t
|
||||
(matchBool
|
||||
(pair (nodePayloadStemChildHash nodePayload) t)
|
||||
(pair (nodePayloadForkLeftHash nodePayload)
|
||||
(pair (nodePayloadForkRightHash nodePayload) t))
|
||||
(nodePayloadStem? nodePayload))
|
||||
(nodePayloadLeaf? nodePayload))
|
||||
(nodeRecordPayload nodeRecord))
|
||||
|
||||
nodeHashPresent? = (nodeHash nodeRecords : nodeRecordsHaveHash? nodeRecords nodeHash)
|
||||
|
||||
nodeChildHashesPresent? = y (self childHashes nodeRecords :
|
||||
matchList
|
||||
true
|
||||
(childHash rest :
|
||||
and?
|
||||
(nodeHashPresent? childHash nodeRecords)
|
||||
(self rest nodeRecords))
|
||||
childHashes)
|
||||
|
||||
nodeRecordChildrenPresent? = (nodeRecord nodeRecords :
|
||||
nodeChildHashesPresent? (nodeRecordChildHashes nodeRecord) nodeRecords)
|
||||
|
||||
nodeRecordsClosed? = y (self nodeRecords allNodeRecords :
|
||||
matchList
|
||||
true
|
||||
(nodeRecord rest :
|
||||
and?
|
||||
(nodeRecordChildrenPresent? nodeRecord allNodeRecords)
|
||||
(self rest allNodeRecords))
|
||||
nodeRecords)
|
||||
|
||||
validateNodeRecords = (nodeRecords rest :
|
||||
matchBool
|
||||
(err errInvalidNodePayload rest)
|
||||
(matchBool
|
||||
(err errDuplicateNode rest)
|
||||
(matchBool
|
||||
(ok nodeRecords rest)
|
||||
(err errMissingNode rest)
|
||||
(nodeRecordsClosed? nodeRecords nodeRecords))
|
||||
(nodeRecordsHaveDuplicateHashes? nodeRecords))
|
||||
(nodeRecordsHaveInvalidPayload? nodeRecords))
|
||||
|
||||
readNodeRecords_ = y (self bs nodeCount i acc :
|
||||
matchBool
|
||||
(ok (reverse acc) bs)
|
||||
(bindResult (readNodeRecord bs)
|
||||
(nodeRecord afterNodeRecord :
|
||||
self afterNodeRecord nodeCount (succ i) (pair nodeRecord acc)))
|
||||
(equal? i nodeCount))
|
||||
|
||||
readNodeRecords = (nodeCount bs : readNodeRecords_ bs nodeCount 0 t)
|
||||
|
||||
readNodesSection = (bs :
|
||||
bindResult (readBytes 8 bs)
|
||||
(nodeCount afterNodeCount :
|
||||
bindResult (readNodeRecords (u64BEBytesToNat nodeCount) afterNodeCount)
|
||||
(nodeRecords afterNodeRecords :
|
||||
bindResult (validateNodeRecords nodeRecords afterNodeRecords)
|
||||
(validNodeRecords afterValidNodeRecords :
|
||||
ok (pair nodeCount validNodeRecords) afterValidNodeRecords))))
|
||||
|
||||
readNodesSectionComplete = (bs :
|
||||
bindResult (readNodesSection bs)
|
||||
(nodesSection afterNodesSection :
|
||||
matchBool
|
||||
(ok nodesSection afterNodesSection)
|
||||
(err errUnexpectedBytes afterNodesSection)
|
||||
(bytesNil? afterNodesSection)))
|
||||
|
||||
readArboricxNodesSection = (bs :
|
||||
bindResult (readArboricxContainer bs)
|
||||
(container afterContainer :
|
||||
matchPair
|
||||
(_ directory :
|
||||
bindResult (sectionBytesOrErr arboricxNodesSectionId directory bs afterContainer)
|
||||
(nodesBytes _ :
|
||||
bindResult (readNodesSectionComplete nodesBytes)
|
||||
(nodesSection _ : ok nodesSection afterContainer)))
|
||||
container))
|
||||
|
||||
nodesSectionCount = (nodesSection :
|
||||
matchPair
|
||||
(nodeCount _ : nodeCount)
|
||||
nodesSection)
|
||||
|
||||
nodesSectionRecords = (nodesSection :
|
||||
matchPair
|
||||
(_ nodeRecords : nodeRecords)
|
||||
nodesSection)
|
||||
|
||||
nodeRecordToTreeWith = (self nodeRecords nodeRecord :
|
||||
(nodePayload :
|
||||
matchBool
|
||||
(ok t t)
|
||||
(matchBool
|
||||
(bindResult (self (nodePayloadStemChildHash nodePayload) nodeRecords)
|
||||
(child _ : ok (t child) t))
|
||||
(bindResult (self (nodePayloadForkLeftHash nodePayload) nodeRecords)
|
||||
(left _ :
|
||||
bindResult (self (nodePayloadForkRightHash nodePayload) nodeRecords)
|
||||
(right _ : ok (pair left right) t)))
|
||||
(nodePayloadStem? nodePayload))
|
||||
(nodePayloadLeaf? nodePayload))
|
||||
(nodeRecordPayload nodeRecord))
|
||||
|
||||
nodeHashToTree = y (self nodeHash nodeRecords :
|
||||
triage
|
||||
(err errMissingNode t)
|
||||
(nodeRecord : nodeRecordToTreeWith self nodeRecords nodeRecord)
|
||||
(_ _ : err errMissingNode t)
|
||||
(lookupNodeRecord nodeHash nodeRecords))
|
||||
|
||||
readArboricxTreeFromHash = (rootHash bs :
|
||||
bindResult (readArboricxNodesSection bs)
|
||||
(nodesSection afterContainer :
|
||||
bindResult (nodeHashToTree rootHash (nodesSectionRecords nodesSection))
|
||||
(tree _ : ok tree afterContainer)))
|
||||
|
||||
readArboricxExecutableFromHash = readArboricxTreeFromHash
|
||||
666
lib/arboricx.tri
666
lib/arboricx.tri
@@ -1,654 +1,18 @@
|
||||
!import "base.tri" !Local
|
||||
!import "list.tri" !Local
|
||||
!import "bytes.tri" !Local
|
||||
!import "binary.tri" !Local
|
||||
!import "arboricx-manifest.tri" !Local
|
||||
|
||||
arboricxMagic = [(65) (82) (66) (79) (82) (73) (67) (88)]
|
||||
arboricxMajorVersion = [(0) (1)]
|
||||
arboricxMinorVersion = [(0) (0)]
|
||||
arboricxManifestSectionId = [(0) (0) (0) (1)]
|
||||
arboricxNodesSectionId = [(0) (0) (0) (2)]
|
||||
|
||||
errMissingSection = 4
|
||||
errUnsupportedVersion = 5
|
||||
errDuplicateSection = 6
|
||||
errDuplicateNode = 7
|
||||
errInvalidNodePayload = 8
|
||||
errMissingNode = 9
|
||||
|
||||
nodePayloadLeafTag = 0
|
||||
nodePayloadStemTag = 1
|
||||
nodePayloadForkTag = 2
|
||||
|
||||
readArboricxMagic = (bs : expectBytes arboricxMagic bs)
|
||||
|
||||
readArboricxHeader = (bs :
|
||||
bindResult (readArboricxMagic bs)
|
||||
(_ afterMagic :
|
||||
bindResult (readBytes 2 afterMagic)
|
||||
(majorVersion afterMajor :
|
||||
bindResult (readBytes 2 afterMajor)
|
||||
(minorVersion afterMinor :
|
||||
bindResult (readBytes 4 afterMinor)
|
||||
(sectionCount afterSectionCount :
|
||||
bindResult (readBytes 8 afterSectionCount)
|
||||
(flags afterFlags :
|
||||
bindResult (readBytes 8 afterFlags)
|
||||
(dirOffset afterDirOffset :
|
||||
ok
|
||||
(pair majorVersion
|
||||
(pair minorVersion
|
||||
(pair sectionCount
|
||||
(pair flags dirOffset))))
|
||||
afterDirOffset)))))))
|
||||
|
||||
readSectionRecord = (bs :
|
||||
bindResult (readBytes 4 bs)
|
||||
(sectionId afterSectionId :
|
||||
bindResult (readBytes 2 afterSectionId)
|
||||
(sectionVersion afterSectionVersion :
|
||||
bindResult (readBytes 2 afterSectionVersion)
|
||||
(sectionFlags afterSectionFlags :
|
||||
bindResult (readBytes 2 afterSectionFlags)
|
||||
(compression afterCompression :
|
||||
bindResult (readBytes 2 afterCompression)
|
||||
(digestAlgorithm afterDigestAlgorithm :
|
||||
bindResult (readBytes 8 afterDigestAlgorithm)
|
||||
(offset afterOffset :
|
||||
bindResult (readBytes 8 afterOffset)
|
||||
(length afterLength :
|
||||
bindResult (readBytes 32 afterLength)
|
||||
(digest afterDigest :
|
||||
ok
|
||||
(pair sectionId
|
||||
(pair sectionVersion
|
||||
(pair sectionFlags
|
||||
(pair compression
|
||||
(pair digestAlgorithm
|
||||
(pair offset
|
||||
(pair length digest)))))))
|
||||
afterDigest)))))))))
|
||||
|
||||
readSectionDirectory_ = y (self bs sectionCount i acc :
|
||||
matchBool
|
||||
(ok (reverse acc) bs)
|
||||
(bindResult (readSectionRecord bs)
|
||||
(sectionRecord afterSectionRecord :
|
||||
self afterSectionRecord sectionCount (succ i) (pair sectionRecord acc)))
|
||||
(equal? i sectionCount))
|
||||
|
||||
readSectionDirectory = (sectionCount bs : readSectionDirectory_ bs sectionCount 0 t)
|
||||
|
||||
sectionRecordId = (sectionRecord :
|
||||
matchPair
|
||||
(sectionId _ : sectionId)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordVersion = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
-- Read and validate a full Arboricx bundle.
|
||||
-- Returns (pair validManifest afterContainer).
|
||||
-- The manifest core fields are validated against expected values.
|
||||
readArboricxBundle = (bs :
|
||||
bindResult (readArboricxRequiredSections bs)
|
||||
(sections afterContainer :
|
||||
matchPair
|
||||
(sectionVersion _ : sectionVersion)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordFlags = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(sectionFlags _ : sectionFlags)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordCompression = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
(manifestBytes _ :
|
||||
bindResult (readManifest manifestBytes)
|
||||
(parsedManifest afterManifest :
|
||||
matchPair
|
||||
(compression _ : compression)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordDigestAlgorithm = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ payload4 :
|
||||
matchPair
|
||||
(digestAlgorithm _ : digestAlgorithm)
|
||||
payload4)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordOffset = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ payload4 :
|
||||
matchPair
|
||||
(_ payload5 :
|
||||
matchPair
|
||||
(offset _ : offset)
|
||||
payload5)
|
||||
payload4)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordLength = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ payload4 :
|
||||
matchPair
|
||||
(_ payload5 :
|
||||
matchPair
|
||||
(_ payload6 :
|
||||
matchPair
|
||||
(length _ : length)
|
||||
payload6)
|
||||
payload5)
|
||||
payload4)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
sectionRecordDigest = (sectionRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ payload4 :
|
||||
matchPair
|
||||
(_ payload5 :
|
||||
matchPair
|
||||
(_ payload6 :
|
||||
matchPair
|
||||
(_ digest : digest)
|
||||
payload6)
|
||||
payload5)
|
||||
payload4)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
sectionRecord)
|
||||
|
||||
lookupSectionRecord_ = y (self directory sectionId :
|
||||
matchList
|
||||
nothing
|
||||
(sectionRecord rest :
|
||||
matchBool
|
||||
(just sectionRecord)
|
||||
(self rest sectionId)
|
||||
(bytesEq? sectionId (sectionRecordId sectionRecord)))
|
||||
directory)
|
||||
|
||||
lookupSectionRecord = (sectionId directory : lookupSectionRecord_ directory sectionId)
|
||||
|
||||
sectionDirectoryHasId?_ = y (self directory sectionId :
|
||||
matchList
|
||||
false
|
||||
(sectionRecord rest :
|
||||
or?
|
||||
(bytesEq? sectionId (sectionRecordId sectionRecord))
|
||||
(self rest sectionId))
|
||||
directory)
|
||||
|
||||
sectionDirectoryHasId? = (sectionId directory : sectionDirectoryHasId?_ directory sectionId)
|
||||
|
||||
sectionDirectoryHasDuplicateIds? = y (self directory :
|
||||
matchList
|
||||
false
|
||||
(sectionRecord rest :
|
||||
or?
|
||||
(sectionDirectoryHasId?_ rest (sectionRecordId sectionRecord))
|
||||
(self rest))
|
||||
directory)
|
||||
|
||||
validateSectionDirectory = (directory rest :
|
||||
matchBool
|
||||
(err errDuplicateSection rest)
|
||||
(ok directory rest)
|
||||
(sectionDirectoryHasDuplicateIds? directory))
|
||||
|
||||
byteSlice = (offset length bytes : bytesTake length (bytesDrop offset bytes))
|
||||
|
||||
natMake = (bit rest :
|
||||
matchBool
|
||||
0
|
||||
(pair bit rest)
|
||||
(and? (equal? bit 0) (equal? rest 0)))
|
||||
|
||||
natAdd = y (self a b :
|
||||
triage
|
||||
b
|
||||
(_ : b)
|
||||
(aBit aRest :
|
||||
triage
|
||||
a
|
||||
(_ : a)
|
||||
(bBit bRest :
|
||||
matchBool
|
||||
(natMake 0 (succ (self aRest bRest)))
|
||||
(natMake (matchBool (matchBool 0 1 bBit) (matchBool 1 0 bBit) aBit)
|
||||
(self aRest bRest))
|
||||
(and? (equal? aBit 1) (equal? bBit 1)))
|
||||
b)
|
||||
a)
|
||||
|
||||
natDouble = (n : matchBool 0 (pair 0 n) (equal? n 0))
|
||||
|
||||
natTimes256 = (n :
|
||||
natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble
|
||||
(natDouble n))))))))
|
||||
|
||||
byteNatShiftAppend_ = y (self byte acc i :
|
||||
matchBool
|
||||
acc
|
||||
(triage
|
||||
(natMake 0 (self 0 acc (succ i)))
|
||||
(_ : acc)
|
||||
(bit rest : natMake bit (self rest acc (succ i)))
|
||||
byte)
|
||||
(equal? i 8))
|
||||
|
||||
byteNatShiftAppend = (byte acc : byteNatShiftAppend_ byte acc 0)
|
||||
|
||||
beBytesToNat = (bytes :
|
||||
foldl
|
||||
(acc byte : byteNatShiftAppend byte acc)
|
||||
0
|
||||
bytes)
|
||||
|
||||
u32BEBytesToNat = beBytesToNat
|
||||
u64BEBytesToNat = beBytesToNat
|
||||
|
||||
arboricxHeaderMajorVersion = (header :
|
||||
matchPair
|
||||
(majorVersion _ : majorVersion)
|
||||
header)
|
||||
|
||||
arboricxHeaderMinorVersion = (header :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(minorVersion _ : minorVersion)
|
||||
payload)
|
||||
header)
|
||||
|
||||
arboricxHeaderSectionCount = (header :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(sectionCount _ : sectionCount)
|
||||
payload2)
|
||||
payload)
|
||||
header)
|
||||
|
||||
arboricxHeaderFlags = (header :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(flags _ : flags)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
header)
|
||||
|
||||
arboricxHeaderDirOffset = (header :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ payload2 :
|
||||
matchPair
|
||||
(_ payload3 :
|
||||
matchPair
|
||||
(_ dirOffset : dirOffset)
|
||||
payload3)
|
||||
payload2)
|
||||
payload)
|
||||
header)
|
||||
|
||||
validateArboricxHeader = (header rest :
|
||||
matchBool
|
||||
(ok header rest)
|
||||
(err errUnsupportedVersion rest)
|
||||
(and?
|
||||
(bytesEq? arboricxMajorVersion (arboricxHeaderMajorVersion header))
|
||||
(bytesEq? arboricxMinorVersion (arboricxHeaderMinorVersion header))))
|
||||
|
||||
readArboricxContainer = (bs :
|
||||
bindResult (readArboricxHeader bs)
|
||||
(header afterHeader :
|
||||
bindResult (validateArboricxHeader header afterHeader)
|
||||
(validHeader afterValidHeader :
|
||||
bindResult (readSectionDirectory
|
||||
(u32BEBytesToNat (arboricxHeaderSectionCount validHeader))
|
||||
(bytesDrop (u64BEBytesToNat (arboricxHeaderDirOffset validHeader)) bs))
|
||||
(directory afterDirectory :
|
||||
bindResult (validateSectionDirectory directory afterDirectory)
|
||||
(validDirectory afterValidDirectory :
|
||||
ok (pair validHeader validDirectory) afterValidDirectory)))))
|
||||
|
||||
sectionRecordOffsetNat = (sectionRecord :
|
||||
u64BEBytesToNat (sectionRecordOffset sectionRecord))
|
||||
|
||||
sectionRecordLengthNat = (sectionRecord :
|
||||
u64BEBytesToNat (sectionRecordLength sectionRecord))
|
||||
|
||||
extractSectionBytes = (sectionRecord containerBytes :
|
||||
byteSlice
|
||||
(sectionRecordOffsetNat sectionRecord)
|
||||
(sectionRecordLengthNat sectionRecord)
|
||||
containerBytes)
|
||||
|
||||
extractSectionBytesResult = (sectionRecord containerBytes rest :
|
||||
(sectionBytes :
|
||||
matchBool
|
||||
(ok sectionBytes rest)
|
||||
(err errUnexpectedEof rest)
|
||||
(equal? (bytesLength sectionBytes) (sectionRecordLengthNat sectionRecord)))
|
||||
(extractSectionBytes sectionRecord containerBytes))
|
||||
|
||||
lookupSectionBytes = (sectionId directory containerBytes :
|
||||
triage
|
||||
nothing
|
||||
(sectionRecord : just (extractSectionBytes sectionRecord containerBytes))
|
||||
(_ _ : nothing)
|
||||
(lookupSectionRecord sectionId directory))
|
||||
|
||||
sectionBytesOrErr = (sectionId directory containerBytes rest :
|
||||
triage
|
||||
(err errMissingSection rest)
|
||||
(sectionRecord : extractSectionBytesResult sectionRecord containerBytes rest)
|
||||
(_ _ : err errMissingSection rest)
|
||||
(lookupSectionRecord sectionId directory))
|
||||
|
||||
readArboricxSectionBytes = (sectionId bs :
|
||||
bindResult (readArboricxContainer bs)
|
||||
(container afterContainer :
|
||||
matchPair
|
||||
(_ directory : sectionBytesOrErr sectionId directory bs afterContainer)
|
||||
container))
|
||||
|
||||
readArboricxRequiredSections = (bs :
|
||||
bindResult (readArboricxContainer bs)
|
||||
(container afterContainer :
|
||||
matchPair
|
||||
(_ directory :
|
||||
bindResult (sectionBytesOrErr arboricxManifestSectionId directory bs afterContainer)
|
||||
(manifestBytes _ :
|
||||
bindResult (sectionBytesOrErr arboricxNodesSectionId directory bs afterContainer)
|
||||
(nodesBytes _ :
|
||||
ok (pair manifestBytes nodesBytes) afterContainer)))
|
||||
container))
|
||||
|
||||
readNodeRecord = (bs :
|
||||
bindResult (readBytes 32 bs)
|
||||
(nodeHash afterNodeHash :
|
||||
bindResult (readBytes 4 afterNodeHash)
|
||||
(payloadLength afterPayloadLength :
|
||||
bindResult (readBytes (u32BEBytesToNat payloadLength) afterPayloadLength)
|
||||
(payload afterPayload :
|
||||
ok
|
||||
(pair nodeHash
|
||||
(pair payloadLength payload))
|
||||
afterPayload))))
|
||||
|
||||
nodeRecordHash = (nodeRecord :
|
||||
matchPair
|
||||
(nodeHash _ : nodeHash)
|
||||
nodeRecord)
|
||||
|
||||
nodeRecordPayloadLength = (nodeRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(payloadLength _ : payloadLength)
|
||||
payload)
|
||||
nodeRecord)
|
||||
|
||||
nodeRecordPayload = (nodeRecord :
|
||||
matchPair
|
||||
(_ payload :
|
||||
matchPair
|
||||
(_ nodePayload : nodePayload)
|
||||
payload)
|
||||
nodeRecord)
|
||||
|
||||
nodePayloadKind = (nodePayload : bytesHead nodePayload)
|
||||
|
||||
nodePayloadHasTag? = (tag nodePayload :
|
||||
triage
|
||||
false
|
||||
(actualTag : byteEq? actualTag tag)
|
||||
(_ _ : false)
|
||||
(nodePayloadKind nodePayload))
|
||||
|
||||
nodePayloadLeaf? = (nodePayload : bytesEq? [(0)] nodePayload)
|
||||
|
||||
nodePayloadStem? = (nodePayload :
|
||||
and?
|
||||
(nodePayloadHasTag? nodePayloadStemTag nodePayload)
|
||||
(equal? (bytesLength nodePayload) 33))
|
||||
|
||||
nodePayloadFork? = (nodePayload :
|
||||
and?
|
||||
(nodePayloadHasTag? nodePayloadForkTag nodePayload)
|
||||
(equal? (bytesLength nodePayload) 65))
|
||||
|
||||
nodePayloadValid? = (nodePayload :
|
||||
or?
|
||||
(nodePayloadLeaf? nodePayload)
|
||||
(or?
|
||||
(nodePayloadStem? nodePayload)
|
||||
(nodePayloadFork? nodePayload)))
|
||||
|
||||
nodePayloadStemChildHash = (nodePayload : bytesTake 32 (bytesDrop 1 nodePayload))
|
||||
nodePayloadForkLeftHash = (nodePayload : bytesTake 32 (bytesDrop 1 nodePayload))
|
||||
nodePayloadForkRightHash = (nodePayload : bytesTake 32 (bytesDrop 33 nodePayload))
|
||||
|
||||
nodeRecordPayloadValid? = (nodeRecord : nodePayloadValid? (nodeRecordPayload nodeRecord))
|
||||
|
||||
nodeRecordsHaveInvalidPayload? = y (self nodeRecords :
|
||||
matchList
|
||||
false
|
||||
(nodeRecord rest :
|
||||
or?
|
||||
(not? (nodeRecordPayloadValid? nodeRecord))
|
||||
(self rest))
|
||||
nodeRecords)
|
||||
|
||||
nodeRecordsHaveHash? = y (self nodeRecords nodeHash :
|
||||
matchList
|
||||
false
|
||||
(nodeRecord rest :
|
||||
or?
|
||||
(bytesEq? nodeHash (nodeRecordHash nodeRecord))
|
||||
(self rest nodeHash))
|
||||
nodeRecords)
|
||||
|
||||
nodeRecordsHaveDuplicateHashes? = y (self nodeRecords :
|
||||
matchList
|
||||
false
|
||||
(nodeRecord rest :
|
||||
or?
|
||||
(nodeRecordsHaveHash? rest (nodeRecordHash nodeRecord))
|
||||
(self rest))
|
||||
nodeRecords)
|
||||
|
||||
lookupNodeRecord_ = y (self nodeRecords nodeHash :
|
||||
matchList
|
||||
nothing
|
||||
(nodeRecord rest :
|
||||
matchBool
|
||||
(just nodeRecord)
|
||||
(self rest nodeHash)
|
||||
(bytesEq? nodeHash (nodeRecordHash nodeRecord)))
|
||||
nodeRecords)
|
||||
|
||||
lookupNodeRecord = (nodeHash nodeRecords : lookupNodeRecord_ nodeRecords nodeHash)
|
||||
|
||||
nodeRecordChildHashes = (nodeRecord :
|
||||
(nodePayload :
|
||||
matchBool
|
||||
t
|
||||
(matchBool
|
||||
(pair (nodePayloadStemChildHash nodePayload) t)
|
||||
(pair (nodePayloadForkLeftHash nodePayload)
|
||||
(pair (nodePayloadForkRightHash nodePayload) t))
|
||||
(nodePayloadStem? nodePayload))
|
||||
(nodePayloadLeaf? nodePayload))
|
||||
(nodeRecordPayload nodeRecord))
|
||||
|
||||
nodeHashPresent? = (nodeHash nodeRecords : nodeRecordsHaveHash? nodeRecords nodeHash)
|
||||
|
||||
nodeChildHashesPresent? = y (self childHashes nodeRecords :
|
||||
matchList
|
||||
true
|
||||
(childHash rest :
|
||||
and?
|
||||
(nodeHashPresent? childHash nodeRecords)
|
||||
(self rest nodeRecords))
|
||||
childHashes)
|
||||
|
||||
nodeRecordChildrenPresent? = (nodeRecord nodeRecords :
|
||||
nodeChildHashesPresent? (nodeRecordChildHashes nodeRecord) nodeRecords)
|
||||
|
||||
nodeRecordsClosed? = y (self nodeRecords allNodeRecords :
|
||||
matchList
|
||||
true
|
||||
(nodeRecord rest :
|
||||
and?
|
||||
(nodeRecordChildrenPresent? nodeRecord allNodeRecords)
|
||||
(self rest allNodeRecords))
|
||||
nodeRecords)
|
||||
|
||||
validateNodeRecords = (nodeRecords rest :
|
||||
matchBool
|
||||
(err errInvalidNodePayload rest)
|
||||
(matchBool
|
||||
(err errDuplicateNode rest)
|
||||
(matchBool
|
||||
(ok nodeRecords rest)
|
||||
(err errMissingNode rest)
|
||||
(nodeRecordsClosed? nodeRecords nodeRecords))
|
||||
(nodeRecordsHaveDuplicateHashes? nodeRecords))
|
||||
(nodeRecordsHaveInvalidPayload? nodeRecords))
|
||||
|
||||
readNodeRecords_ = y (self bs nodeCount i acc :
|
||||
matchBool
|
||||
(ok (reverse acc) bs)
|
||||
(bindResult (readNodeRecord bs)
|
||||
(nodeRecord afterNodeRecord :
|
||||
self afterNodeRecord nodeCount (succ i) (pair nodeRecord acc)))
|
||||
(equal? i nodeCount))
|
||||
|
||||
readNodeRecords = (nodeCount bs : readNodeRecords_ bs nodeCount 0 t)
|
||||
|
||||
readNodesSection = (bs :
|
||||
bindResult (readBytes 8 bs)
|
||||
(nodeCount afterNodeCount :
|
||||
bindResult (readNodeRecords (u64BEBytesToNat nodeCount) afterNodeCount)
|
||||
(nodeRecords afterNodeRecords :
|
||||
bindResult (validateNodeRecords nodeRecords afterNodeRecords)
|
||||
(validNodeRecords afterValidNodeRecords :
|
||||
ok (pair nodeCount validNodeRecords) afterValidNodeRecords))))
|
||||
|
||||
readNodesSectionComplete = (bs :
|
||||
bindResult (readNodesSection bs)
|
||||
(nodesSection afterNodesSection :
|
||||
matchBool
|
||||
(ok nodesSection afterNodesSection)
|
||||
(err errUnexpectedBytes afterNodesSection)
|
||||
(bytesNil? afterNodesSection)))
|
||||
|
||||
readArboricxNodesSection = (bs :
|
||||
bindResult (readArboricxContainer bs)
|
||||
(container afterContainer :
|
||||
matchPair
|
||||
(_ directory :
|
||||
bindResult (sectionBytesOrErr arboricxNodesSectionId directory bs afterContainer)
|
||||
(nodesBytes _ :
|
||||
bindResult (readNodesSectionComplete nodesBytes)
|
||||
(nodesSection _ : ok nodesSection afterContainer)))
|
||||
container))
|
||||
|
||||
nodesSectionCount = (nodesSection :
|
||||
matchPair
|
||||
(nodeCount _ : nodeCount)
|
||||
nodesSection)
|
||||
|
||||
nodesSectionRecords = (nodesSection :
|
||||
matchPair
|
||||
(_ nodeRecords : nodeRecords)
|
||||
nodesSection)
|
||||
|
||||
nodeRecordToTreeWith = (self nodeRecords nodeRecord :
|
||||
(nodePayload :
|
||||
matchBool
|
||||
(ok t t)
|
||||
(matchBool
|
||||
(bindResult (self (nodePayloadStemChildHash nodePayload) nodeRecords)
|
||||
(child _ : ok (t child) t))
|
||||
(bindResult (self (nodePayloadForkLeftHash nodePayload) nodeRecords)
|
||||
(left _ :
|
||||
bindResult (self (nodePayloadForkRightHash nodePayload) nodeRecords)
|
||||
(right _ : ok (pair left right) t)))
|
||||
(nodePayloadStem? nodePayload))
|
||||
(nodePayloadLeaf? nodePayload))
|
||||
(nodeRecordPayload nodeRecord))
|
||||
|
||||
nodeHashToTree = y (self nodeHash nodeRecords :
|
||||
triage
|
||||
(err errMissingNode t)
|
||||
(nodeRecord : nodeRecordToTreeWith self nodeRecords nodeRecord)
|
||||
(_ _ : err errMissingNode t)
|
||||
(lookupNodeRecord nodeHash nodeRecords))
|
||||
|
||||
readArboricxTreeFromHash = (rootHash bs :
|
||||
bindResult (readArboricxNodesSection bs)
|
||||
(nodesSection afterContainer :
|
||||
bindResult (nodeHashToTree rootHash (nodesSectionRecords nodesSection))
|
||||
(tree _ : ok tree afterContainer)))
|
||||
|
||||
readArboricxExecutableFromHash = readArboricxTreeFromHash
|
||||
(coreManifest metadataWithExtensions :
|
||||
bindResult (validateManifestCore coreManifest afterManifest)
|
||||
(validCore _ : ok (pair validCore metadataWithExtensions) afterContainer))
|
||||
parsedManifest))
|
||||
sections))
|
||||
|
||||
Reference in New Issue
Block a user