in Sources/SIL/SILParser.swift [104:363]
func parseInstructionBody(_ instructionName: String) throws -> Instruction {
switch instructionName {
case "alloc_stack":
let type = try parseType()
let attributes = try parseUntilNil { try parseDebugAttribute() }
return .operator(.allocStack(type, attributes))
case "apply":
let nothrow = skip("[nothrow]")
let value = try parseValue()
let substitutions = try parseNilOrMany("<", ",", ">") { try parseNakedType() } ?? []
let arguments = try parseMany("(", ",", ")") { try parseValue() }
try take(":")
let type = try parseType()
return .operator(.apply(nothrow, value, substitutions, arguments, type))
case "begin_access":
try take("[")
let access = try parseAccess()
try take("]")
try take("[")
let enforcement = try parseEnforcement()
try take("]")
let noNestedConflict = skip("[no_nested_conflict]")
let builtin = skip("[builtin]")
let operand = try parseOperand()
return .operator(.beginAccess(access, enforcement, noNestedConflict, builtin, operand))
case "begin_apply":
let nothrow = skip("[nothrow]")
let value = try parseValue()
let substitutions = try parseNilOrMany("<", ",", ">") { try parseNakedType() } ?? []
let arguments = try parseMany("(", ",", ")") { try parseValue() }
try take(":")
let type = try parseType()
return .operator(.beginApply(nothrow, value, substitutions, arguments, type))
case "begin_borrow":
let operand = try parseOperand()
return .operator(.beginBorrow(operand))
case "br":
let label = try parseIdentifier()
let operands = try parseNilOrMany("(", ",", ")") { try parseOperand() } ?? []
return .terminator(.br(label, operands))
case "builtin":
let name = try parseString()
let operands = try parseMany("(", ",", ")") { try parseOperand() }
try take(":")
let type = try parseType()
return .operator(.builtin(name, operands, type))
case "cond_br":
let cond = try parseValueName()
try take(",")
let trueLabel = try parseIdentifier()
let trueOperands = try parseNilOrMany("(", ",", ")") { try parseOperand() } ?? []
try take(",")
let falseLabel = try parseIdentifier()
let falseOperands = try parseNilOrMany("(", ",", ")") { try parseOperand() } ?? []
return .terminator(.condBr(cond, trueLabel, trueOperands, falseLabel, falseOperands))
case "cond_fail":
let operand = try parseOperand()
try take(",")
let message = try parseString()
return .operator(.condFail(operand, message))
case "convert_escape_to_noescape":
let notGuaranteed = skip("[not_guaranteed]")
let escaped = skip("[escaped]")
let operand = try parseOperand()
try take("to")
let type = try parseType()
return .operator(.convertEscapeToNoescape(notGuaranteed, escaped, operand, type))
case "convert_function":
let operand = try parseOperand()
try take("to")
let withoutActuallyEscaping = skip("[without_actually_escaping]")
let type = try parseType()
return .operator(.convertFunction(operand, withoutActuallyEscaping, type))
case "copy_addr":
let take = skip("[take]")
let value = try parseValue()
try self.take("to")
let initialization = skip("[initialization]")
let operand = try parseOperand()
return .operator(.copyAddr(take, value, initialization, operand))
case "copy_value":
let operand = try parseOperand()
return .operator(.copyValue(operand))
case "dealloc_stack":
let operand = try parseOperand()
return .operator(.deallocStack(operand))
case "debug_value":
let operand = try parseOperand()
let attributes = try parseUntilNil { try parseDebugAttribute() }
return .operator(.debugValue(operand, attributes))
case "debug_value_addr":
let operand = try parseOperand()
let attributes = try parseUntilNil { try parseDebugAttribute() }
return .operator(.debugValueAddr(operand, attributes))
case "destroy_value":
let operand = try parseOperand()
return .operator(.destroyValue(operand))
case "destructure_tuple":
let operand = try parseOperand()
return .operator(.destructureTuple(operand))
case "end_access":
let abort = skip("[abort]")
let operand = try parseOperand()
return .operator(.endAccess(abort, operand))
case "end_apply":
let value = try parseValue()
return .operator(.endApply(value))
case "end_borrow":
let operand = try parseOperand()
return .operator(.endBorrow(operand))
case "enum":
let type = try parseType()
try take(",")
let declRef = try parseDeclRef()
let operand = skip(",") ? try parseOperand() : nil
return .operator(.enum(type, declRef, operand))
case "float_literal":
let type = try parseType()
try take(",")
try take("0x")
let value = take(while: { $0.isHexDigit })
return .operator(.floatLiteral(type, value))
case "function_ref":
let name = try parseGlobalName()
try take(":")
let type = try parseType()
return .operator(.functionRef(name, type))
case "global_addr":
let name = try parseGlobalName()
try take(":")
let type = try parseType()
return .operator(.globalAddr(name, type))
case "index_addr":
let addr = try parseOperand()
try take(",")
let index = try parseOperand()
return .operator(.indexAddr(addr, index))
case "integer_literal":
let type = try parseType()
try take(",")
let value = try parseInt()
return .operator(.integerLiteral(type, value))
case "load":
var ownership: LoadOwnership?
if skip("[copy]") {
ownership = .copy
} else if skip("[take]") {
ownership = .take
} else if skip("[trivial]") {
ownership = .trivial
}
let operand = try parseOperand()
return .operator(.load(ownership, operand))
case "metatype":
let type = try parseType()
return .operator(.metatype(type))
case "mark_dependence":
let operand = try parseOperand()
try take("on")
let on = try parseOperand()
return .operator(.markDependence(operand, on))
case "partial_apply":
let calleeGuaranteed = skip("[callee_guaranteed]")
let onStack = skip("[on_stack]")
let value = try parseValue()
let substitutions = try parseNilOrMany("<", ",", ">") { try parseNakedType() } ?? []
let arguments = try parseMany("(", ",", ")") { try parseValue() }
try take(":")
let type = try parseType()
return .operator(.partialApply(calleeGuaranteed, onStack, value, substitutions, arguments, type))
case "pointer_to_address":
let operand = try parseOperand()
try take("to")
let strict = skip("[strict]")
let type = try parseType()
return .operator(.pointerToAddress(operand, strict, type))
case "return":
let operand = try parseOperand()
return .terminator(.return(operand))
case "release_value":
let operand = try parseOperand()
return .operator(.releaseValue(operand))
case "retain_value":
let operand = try parseOperand()
return .operator(.retainValue(operand))
case "select_enum":
let operand = try parseOperand()
let cases = try parseUntilNil { try parseCase(parseValue) }
try take(":")
let type = try parseType()
return .operator(.selectEnum(operand, cases, type))
case "store":
let value = try parseValue()
try take("to")
var ownership: StoreOwnership?
if skip("[init]") {
ownership = .init
} else if skip("[trivial]") {
ownership = .trivial
}
let operand = try parseOperand()
return .operator(.store(value, ownership, operand))
case "string_literal":
let encoding = try parseEncoding()
let value = try parseString()
return .operator(.stringLiteral(encoding, value))
case "strong_release":
let operand = try parseOperand()
return .operator(.strongRelease(operand))
case "strong_retain":
let operand = try parseOperand()
return .operator(.strongRetain(operand))
case "struct":
let type = try parseType()
let operands = try parseMany("(", ",", ")") { try parseOperand() }
return .operator(.struct(type, operands))
case "struct_element_addr":
let operand = try parseOperand()
try take(",")
let declRef = try parseDeclRef()
return .operator(.structElementAddr(operand, declRef))
case "struct_extract":
let operand = try parseOperand()
try take(",")
let declRef = try parseDeclRef()
return .operator(.structExtract(operand, declRef))
case "switch_enum":
let operand = try parseOperand()
let cases = try parseUntilNil { try parseCase(parseIdentifier) }
return .terminator(.switchEnum(operand, cases))
case "thin_to_thick_function":
let operand = try parseOperand()
try take("to")
let type = try parseType()
return .operator(.thinToThickFunction(operand, type))
case "tuple":
let elements = try parseTupleElements()
return .operator(.tuple(elements))
case "tuple_extract":
let operand = try parseOperand()
try take(",")
let declRef = try parseInt()
return .operator(.tupleExtract(operand, declRef))
case "unreachable":
return .terminator(.unreachable)
case "witness_method":
let archeType = try parseType()
try take(",")
let declRef = try parseDeclRef()
try take(":")
let declType = try parseNakedType()
try take(":")
let type = try parseType()
return .operator(.witnessMethod(archeType, declRef, declType, type))
default:
// TODO(#8): Actually parse this instruction.
let _ = skip(while: { $0 != "\n" })
return .operator(.unknown(instructionName))
}
}