in Sources/_MatchingEngine/Engine/Processor.swift [189:404]
mutating func cycle() {
_checkInvariants()
assert(state == .inProgress)
if cycleCount == 0 { trace() }
defer {
cycleCount += 1
trace()
_checkInvariants()
}
let (opcode, payload) = fetch().destructure
switch opcode {
case .invalid:
fatalError("Invalid program")
case .nop:
if checkComments,
let s = payload.optionalString
{
doPrint(registers[s])
}
controller.step()
case .decrement:
let (bool, int) = payload.pairedBoolInt
let newValue = registers[int] - 1
registers[bool] = newValue == 0
registers[int] = newValue
controller.step()
case .moveImmediate:
let (imm, reg) = payload.pairedImmediateInt
let int = Int(asserting: imm)
assert(int == imm)
registers[reg] = int
controller.step()
case .movePosition:
let reg = payload.position
registers[reg] = currentPosition
controller.step()
case .branch:
controller.pc = payload.addr
case .condBranch:
let (addr, cond) = payload.pairedAddrBool
if registers[cond] {
controller.pc = addr
} else {
controller.step()
}
case .condBranchZeroElseDecrement:
let (addr, int) = payload.pairedAddrInt
if registers[int] == 0 {
controller.pc = addr
} else {
registers[int] -= 1
controller.step()
}
case .save:
let resumeAddr = payload.addr
let sp = makeSavePoint(resumeAddr)
savePoints.append(sp)
controller.step()
case .saveAddress:
let resumeAddr = payload.addr
let sp = makeSavePoint(resumeAddr, addressOnly: true)
savePoints.append(sp)
controller.step()
case .splitSaving:
let (nextPC, resumeAddr) = payload.pairedAddrAddr
let sp = makeSavePoint(resumeAddr)
savePoints.append(sp)
controller.pc = nextPC
case .clear:
if let _ = savePoints.popLast() {
controller.step()
} else {
fatalError("TODO: What should we do here?")
}
case .peek:
fatalError()
case .restore:
signalFailure()
case .push:
fatalError()
case .pop:
fatalError()
case .call:
controller.step()
callStack.append(controller.pc)
controller.pc = payload.addr
case .ret:
// TODO: Should empty stack mean success?
guard let r = callStack.popLast() else {
tryAccept()
return
}
controller.pc = r
case .abort:
// TODO: throw or otherwise propagate
if let s = payload.optionalString {
doPrint(registers[s])
}
state = .fail
case .accept:
tryAccept()
case .fail:
signalFailure()
case .advance:
if consume(payload.distance) {
controller.step()
}
case .match:
let reg = payload.element
match(registers[reg])
case .matchSequence:
let reg = payload.sequence
let seq = registers[reg]
matchSeq(seq)
case .matchSlice:
let (lower, upper) = payload.pairedPosPos
let range = registers[lower]..<registers[upper]
let slice = input[range]
matchSeq(slice)
case .consumeBy:
let reg = payload.consumer
guard currentPosition < bounds.upperBound,
let nextIndex = registers[reg](
input, currentPosition..<bounds.upperBound)
else {
signalFailure()
return
}
advance(to: nextIndex)
controller.step()
case .assertBy:
let reg = payload.assertion
let assertion = registers[reg]
guard assertion(input, currentPosition, bounds) else {
signalFailure()
return
}
controller.step()
case .print:
// TODO: Debug stream
doPrint(registers[payload.string])
case .assertion:
let (element, cond) =
payload.pairedElementBool
let result: Bool
if let cur = load(), cur == registers[element] {
result = true
} else {
result = false
}
registers[cond] = result
controller.step()
case .backreference:
let capNum = Int(
asserting: payload.capture.rawValue)
guard capNum < storedCaptures.count else {
fatalError("Should this be an assert?")
}
// TODO:
// Should we assert it's not finished yet?
// What's the behavior there?
let cap = storedCaptures[capNum]
guard let range = cap.latest else {
signalFailure()
return
}
matchSeq(input[range])
case .beginCapture:
let capNum = Int(
asserting: payload.capture.rawValue)
let sp = makeSavePoint(self.currentPC)
storedCaptures[capNum].startCapture(
currentPosition, initial: sp)
controller.step()
case .endCapture:
let capNum = Int(
asserting: payload.capture.rawValue)
storedCaptures[capNum].endCapture(currentPosition)
controller.step()
}
}