1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
@testable import _StringProcessing
extension PEG {
// NOTE: We could have a collection-agnostic object code that we compile
// (provided no custom collection hooks are needed) to, and bind later.
// For now, we bind Input with the VM
public struct VM<Input: Collection> where Input.Element == Element {
typealias Core = PEGCore<Input>
typealias Instruction = Core.Instruction
var instructions: InstructionList<Instruction>
var enableTracing: Bool = false
}
}
extension PEG.VM {
struct Loader {
var functionLocations = Dictionary<FunctionId, InstructionAddress>()
// Need second pass to link functions and adjust branches
var functionFixups = Array<(InstructionAddress, FunctionId)>()
// var labelLocations = Dictionary<Code.Label, PC>()
}
static func load(_ code: Code) -> Self {
//
// Lower, layout, link, and load
//
// Layout (currently in `code` order)
var loweredInstructions = Array<Core.Instruction>()
// We will need to do a second pass to adjust function
// references
var functionLocations = Dictionary<FunctionId, InstructionAddress>()
var functionFixups = Array<(InstructionAddress, FunctionId)>()
func add(_ inst: Instruction) {
loweredInstructions.append(inst)
}
func addFunctionFixup(
_ inst: Instruction, _ f: FunctionId
) {
defer { add(inst) }
functionFixups.append((nextPC, f))
}
var nextPC: InstructionAddress { InstructionAddress(loweredInstructions.count) }
let invalidLoc = InstructionAddress(-1)
for funIdx in code.functions.indices {
functionLocations[FunctionId(funIdx)] = nextPC
let fun = code.functions[funIdx]
// We will need to do a second pass to adjust label
// references
var labelFixups = Array<(InstructionAddress, LabelId)>()
var labelLocations = Dictionary<LabelId, InstructionAddress>()
func addLabelFixup(_ inst: Instruction, _ l: LabelId) {
defer { add(inst) }
labelFixups.append((nextPC, l))
}
for inst in fun.instructions {
switch inst {
case .label(let l):
labelLocations[l] = nextPC
case .nop:
continue
case .comment(let s):
if emitComments { add(.comment(s)) }
case .consume(let n):
add(.consume(n))
case .element(let e):
add(.match(e))
case .set(let p):
add(.matchPredicate(p))
case .any:
add(.any)
// Lower labels
case .branch(let l):
addLabelFixup(.branch(to: invalidLoc), l)
case .condBranch(let cond, let l):
addLabelFixup(
.condBranch(condition: cond, to: invalidLoc), l)
case .save(let l):
addLabelFixup(.save(invalidLoc), l)
case .commit(let l):
add(.clear)
addLabelFixup(.branch(to: invalidLoc), l)
// Link calls
case .call(let f):
addFunctionFixup(.call(invalidLoc), f)
case .ret:
add(.ret)
case .startCapture:
fatalError()
case .endCapture:
fatalError()
// TODO:
case .accept:
add(.accept)
case .fail:
add(.fail)
case .abort:
add(.abort(reason: "ABORT!"))
}
}
// Fixup labels
for (pc, l) in labelFixups {
loweredInstructions[
pc.rawValue
].setPC(labelLocations[l]!)
}
}
// Fixup functions
for (pc, f) in functionFixups {
loweredInstructions[
pc.rawValue
].setPC(functionLocations[f]!)
}
return Self(instructions: InstructionList(loweredInstructions))
}
}
extension PEG.VM: CustomStringConvertible {
public var description: String {
instructions.indices.reduce("Instructions:\n") { result, idx in
result + "\(instructions.formatInstruction(idx, atCurrent: false, depth: 3))\n"
}
}
}
|