in Sources/SIL/BitcodeParser.swift [192:257]
func parse() throws -> BitcodeBlock {
if stream.isEmpty {
guard blockStack.count == 1 else {
throw Error.parseError(
"End of stream encountered with some blocks still open")
}
return blockStack[0]
}
let abbrev = try stream.next(bits: currentBlock.abbrLen)
switch (abbrev) {
case endBlock:
// [endBlock, <align32bits>]
stream.align(toMultipleOf: 32)
let _ = blockStack.popLast()
guard !blockStack.isEmpty else {
throw Error.parseError("Unexpected endBlock")
}
return try parse()
case enterSubBlock:
// [enterSubBlock, blockid(vbr8), newabbrevlen(vbr4), <align32bits>, blocklen_32]
let blockId = try read(vbr: 8)
let newAbbrevLenBits = try read(vbr: 4)
stream.align(toMultipleOf: 32)
let blockLen32 = try Int(stream.next(bits: 32).uint32)
let newAbbrevLen = newAbbrevLenBits.int
// BLOCKINFO block is a bit special and we'll reparse it
// into blockInfoTemplates instead of having it as a subblock
if (blockId == blockInfoId) {
try parseInfoBlock(abbrLen: newAbbrevLen)
} else {
var subblockInfo: BitcodeBlockInfo
if let info = blockInfoTemplates[blockId] {
subblockInfo = BitcodeBlockInfo(from: info)
} else {
subblockInfo = BitcodeBlockInfo(id: blockId)
}
let subblock = BitcodeBlock(
info: subblockInfo, abbrLen: newAbbrevLen, blockLen32: blockLen32)
currentBlock.subblocks.append(subblock)
blockStack.append(subblock)
// XXX: At this point subblock is the currentBlock
}
return try parse()
case defineAbbrev:
// NB: Abbreviation IDs are assign in order of their declaration,
// but starting from 4 (because there are 4 builtin abbrevs).
let abbrevId = Bits(currentBlock.info.abbreviations.count + 4)
currentBlock.info.abbreviations[abbrevId] = try parseAbbrevStructure()
return try parse()
case unabbrevRecord:
currentBlock.records.append(try parseUnabbrevRecord())
return try parse()
default: // Abbreviated record
guard let structure = currentBlock.info.abbreviations[abbrev] else {
throw Error.parseError("Undeclared abbreviation: " + abbrev.description)
}
let record = try parseAbbrevRecord(structure)
currentBlock.records.append(record)
return try parse()
}
}